# IAM Authentication for Your Backend

IAM authentication lets your cloud provider decide whether a request from Zuplo
is allowed to reach your backend. Instead of sharing a secret you both store,
your gateway proves its identity to AWS, Azure, or Google Cloud, and your
provider's own authorization rules do the rest.

Zuplo handles this with a set of upstream auth policies. Each one resolves a
credential before your request leaves the gateway, then attaches it — as an
`Authorization` header, or as a signature the handler computes.

This approach suits backends that already run behind cloud IAM: Cloud Run, API
Gateway, Lambda, App Service, Identity-Aware Proxy, or anything fronted by an
identity provider you control. For the alternatives, see
[Securing your backend](./securing-your-backend.mdx).

## Federated identity or stored credentials

Every provider offers two paths, and the choice matters more than which cloud
you're on.

**Federated identity** is the stronger option. Zuplo presents a short-lived,
audience-bound OIDC token that proves which gateway is calling, and your cloud
exchanges it for temporary credentials. No long-lived key exists, so there's
nothing to leak or rotate. Use it when your provider supports it.

**Stored credentials** mean you create a key or client secret in your cloud and
save it as a Zuplo environment variable. This works everywhere and is simpler to
set up, but the credential is long-lived, so you own rotating it.

## Choose a policy

| Provider     | Federated identity                                                                 | Stored credentials                                                                       |
| ------------ | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| AWS          | [Upstream AWS Federated Auth](../policies/upstream-aws-federated-auth-inbound.mdx) | [Upstream AWS Service Auth](../policies/upstream-aws-service-auth-inbound.mdx)           |
| Google Cloud | [Upstream GCP Federated Auth](../policies/upstream-gcp-federated-auth-inbound.mdx) | [Upstream GCP Service Auth](../policies/upstream-gcp-service-auth-inbound.mdx)           |
| Azure        | —                                                                                  | [Upstream Azure AD Service Auth](../policies/upstream-azure-ad-service-auth-inbound.mdx) |

Two more policies cover cases that aren't tied to one cloud:

- [Upstream GCP JWT](../policies/upstream-gcp-jwt-inbound.mdx) issues a signed
  JWT from a service account, for backends that verify a Google-issued token
  rather than calling an IAM-protected endpoint.
- [Upstream OAuth Client Credentials](../policies/upstream-oauth-client-credentials-inbound.mdx)
  handles any backend that accepts an OAuth 2.0 client credentials token,
  including identity providers outside the three major clouds.

Each policy page documents its options and the setup required on the cloud side.

## How AWS differs

The AWS policies behave differently from the others, and it's worth knowing
before you configure a route. They don't add an `Authorization` header. AWS
Signature Version 4 signs the exact final request — method, host, path, query,
and a hash of the body — which isn't known until the handler builds it.

So the AWS policies resolve credentials onto the request context, and the
[AWS Lambda handler](../handlers/aws-lambda.mdx) or your own code signs with
them. In custom code, read them with `AwsClient.fromContext(context)`. When you
use the Lambda handler, attach the policy to the route and omit the handler's
own `accessKeyId` and `secretAccessKey`.

The Azure and GCP policies fetch a token and set the `Authorization` header
themselves, so a URL Rewrite route needs no extra code.

## Keep credentials out of source control

Whichever policy you pick, reference secrets through environment variables
rather than writing them into `policies.json`:

```json title="config/policies.json"
{
  "name": "upstream-auth",
  "policyType": "upstream-azure-ad-service-auth-inbound",
  "handler": {
    "export": "UpstreamAzureAdServiceAuthInboundPolicy",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "activeDirectoryTenantId": "$env(AZURE_TENANT_ID)",
      "activeDirectoryClientId": "$env(AZURE_CLIENT_ID)",
      "activeDirectoryClientSecret": "$env(AZURE_CLIENT_SECRET)"
    }
  }
}
```

Mark each value as a secret when you create it. For per-environment values, see
[Configuring environment variables](./environment-variables.mdx).

## Next steps

- [Secure a GCP backend with Zuplo upstream auth](./gke-with-upstream-auth-policy.mdx)
  — a full walkthrough, including Identity-Aware Proxy.
- [Gateway to origin mTLS authentication](./securing-backend-mtls.mdx) — use
  client certificates instead, when your backend isn't behind cloud IAM.
- [Secure tunnel](./secure-tunnel.mdx) — reach a backend that has no public
  endpoint at all.
