Skip to content

Claude Apps Gateway: SSO, Group Policy, and Spend Caps

By Shoaib HossainJuly 31, 202614 min readUpdated October 17, 2026

Organisations that run Claude through Amazon Bedrock, Google Cloud, or Microsoft Foundry, often for data-residency reasons, used to face a choice: give every developer cloud credentials, or build their own proxy and keep it compatible with every Claude Code release. The Claude apps gateway is Anthropic's answer. It is a self-hosted server built into the claude binary itself (claude gateway --config gateway.yaml), tested with each Claude Code release, that signs developers in with your corporate identity provider and forwards their requests to your provider.

This guide follows the official gateway documentation: what the gateway gives you over a generic proxy, a minimal gateway.yaml, how developers sign in, per-group model access and managed settings, spend caps, failover, and the features that do not work through it. Every config example here is from Anthropic's docs; check the current configuration reference before production, because the gateway is still gaining options with each release.

If you already run an LLM gateway that works, keep it; Claude Code LLM Gateway covers connecting Claude Code to one. For managed settings without a gateway, see Claude Code Enterprise Setup.

Claude apps gateway: developers sign in with corporate SSO, the gateway applies per-group policy, and forwards inference to your cloud provider
Claude apps gateway: developers sign in with corporate SSO, the gateway applies per-group policy, and forwards inference to your cloud provider

What the gateway does that a generic proxy does not

Claude Code clients send ordinary Anthropic Messages requests to the gateway, carrying a short-lived gateway token instead of an API key. The gateway checks the developer's policy and spend, translates the model ID for the upstream (for example claude-opus-4-8 to us.anthropic.claude-opus-4-8 on Bedrock), and forwards the request with the organisation's credential. It provides:

  • Credentials: the upstream key or cloud role lives only on the gateway. Developers sign in with corporate SSO. Deprovision someone in the IdP and their access ends within the session lifetime, one hour by default.
  • Access control: IdP groups map to model allowlists, enforced on the server, and to managed settings that the CLI applies at the top of its settings hierarchy.
  • Settings delivery: the gateway serves managed settings to signed-in clients, taking the place of server-managed settings from the claude.ai console.
  • Telemetry: OTLP metrics with tokens, model, user identity, and latency go to your collectors.
  • Upstream routing: Bedrock, Claude Platform on AWS, Google Cloud's Agent Platform, Microsoft Foundry, or the Anthropic API, with failover between them.

The main difference from a third-party gateway is compatibility. Because it ships with Claude Code, it forwards the anthropic-beta values and request fields each release sends, and moves them into the request body where Bedrock expects them, so you do not maintain an allowlist.

Request path: Claude Code sends Anthropic Messages requests with a gateway token; the gateway checks policy, translates, and calls the upstream
Request path: Claude Code sends Anthropic Messages requests with a gateway token; the gateway checks policy, translates, and calls the upstream

Quick reference

  • The gateway's data plane sends nothing to Anthropic unless the Anthropic API is one of your upstreams. Telemetry, audit logs, settings, and identity stay with you.
  • The gateway does not log or store prompt or completion content.
  • If you do not need your own cloud provider, Anthropic suggests Claude Enterprise may fit better, since it adds features such as SCIM provisioning and Claude Code on the web and mobile.

Remember this

It is a release-matched proxy with SSO, group policy, and spend caps, aimed at organisations that must route through their own cloud.

A minimal gateway.yaml

Prerequisites: Claude Code v2.1.195 or later on the gateway server and on developer machines, an OIDC identity provider (SAML and LDAP are not supported), PostgreSQL 11 or later, an upstream credential, HTTPS, and a hostname that resolves only to private addresses. The server runs on the Linux binary; macOS works for local development.

The minimal file has five sections. Secrets use ${ENV_VAR} expansion so the file can live in version control:

1listen:2  host: 0.0.0.03  port: 80804  public_url: https://claude-gateway.internal.example.com5 6oidc:7  issuer: https://login.example.com8  client_id: 0oa1example29  client_secret: ${OIDC_CLIENT_SECRET}10  allowed_email_domains: [example.com]11 12session:13  jwt_secret: ${GATEWAY_JWT_SECRET}   # openssl rand -base64 3214  ttl_hours: 1                        # also bounds revocation after deprovisioning15 16store:17  postgres_url: ${GATEWAY_POSTGRES_URL}18 19upstreams:20  - provider: bedrock21    region: us-east-122    auth: {}                          # AWS default credential chain23 24auto_include_builtin_models: true

Register an OIDC web application in your IdP with the redirect URI https://<public_url host>/oauth/callback. Run the gateway with claude gateway --config gateway.yaml, or in a container image you build around the claude binary. Boot is fail-closed: if the config, Postgres, OIDC discovery, or upstream client setup fails, the gateway exits with an error naming the problem rather than serving in a degraded state.

Quick reference

  • The Bedrock principal needs bedrock:InvokeModel and bedrock:InvokeModelWithResponseStream on both the inference-profile/us.anthropic.* and foundation-model/anthropic.* ARNs. Use IRSA, an ECS task role, or an instance profile rather than static keys.
  • A successful boot does not prove inference works: Bedrock and Google Cloud credentials resolve on the first request.
  • Expect a warning that access_control.allow_cidrs is empty; set it to your client ranges before production.
  • The private-address rule exists because a trusted gateway can push settings that run commands on developer machines. Put it behind an internal load balancer or VPN.

Remember this

Five sections get a working sign-in loop; boot fails loudly on config, database, or IdP errors.

How developers sign in

Developers do not need a claude.ai account, an API key, or a subscription. Push three keys in the managed settings file on each machine:

1{2  "forceLoginMethod": "gateway",3  "forceLoginGatewayUrl": "https://claude-gateway.internal.example.com",4  "parentSettingsBehavior": "merge"5}

The developer runs /login, presses Enter on the Cloud gateway screen, and completes an OAuth device flow in the browser. On first connect, Claude Code shows the first 16 hex characters of the gateway's TLS certificate fingerprint and pins it per hostname, so publish the expected fingerprint next to the URL. Sessions refresh silently before ttl_hours expires; after IdP deprovisioning the refresh fails and the developer is asked to log in again.

Before sharing the gateway, check it with three requests: GET /.well-known/oauth-authorization-server (boot succeeded), POST /oauth/device_authorization (Postgres reachable and writable), and opening the returned verification_uri_complete in a browser (the IdP redirect works). The first failing check tells you where to look.

Developer sign-in uses the OAuth device flow: /login in Claude Code, confirm in a browser through the IdP, then receive a gateway session
Developer sign-in uses the OAuth device flow: /login in Claude Code, confirm in a browser through the IdP, then receive a gateway session

Quick reference

  • The device flow works over SSH: run /login on a remote box and open the link on your laptop.
  • There is no service-token flow. A CI job with nobody to approve a browser sign-in cannot use the gateway; configure CI against the provider directly.
  • Certificate rotation makes every developer see the trust prompt again, so treat it as a planned event and republish the fingerprint.
  • If an HTTPS proxy sits between laptops and the gateway, add the gateway host to NO_PROXY, or the pin check is skipped and /login may reject the proxy's public address.

Remember this

Managed settings point /login at the gateway; the device flow and a pinned certificate do the rest.

Per-group models and managed settings

The managed.policies list maps IdP groups to the settings each developer gets. Policies are evaluated in order, the first match is selected, and it is merged onto the match: {} catch-all:

1managed:2  policies:3    - match: { groups: [eng-contractors] }4      cli:5        availableModels: [claude-sonnet-4-6]6        permissions: { deny: ["WebFetch", "WebSearch"] }7    - match: {}8      cli:9        availableModels: [claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5]10        enforceAvailableModels: true

The gateway enforces model access itself: a request for a model the policy does not grant returns 400, and the /model picker only shows the policy's allowlist. Everything under cli is applied by the client as managed settings, at startup and on each hourly poll, and locked keys cannot be overridden locally.

Group matching reads the token's groups claim and is case-sensitive. Microsoft Entra ID puts app roles under roles, so set oidc.groups_claim: roles there.

Quick reference

  • An authenticated user who matches no policy gets the gateway defaults: every model in the catalog and no managed settings. Always keep a match: {} catch-all.
  • The login keys (forceLoginMethod, forceLoginGatewayUrl) belong in the file you push to machines, not in managed.policies[].cli, which only reaches clients already connected.
  • Signed-in sessions exit at startup after about 10 seconds if the gateway is unreachable, rather than running without their settings.

Remember this

One ordered list of group policies controls models and settings; keep the catch-all last and check the group claim name.

Spend caps and upstream failover

With an admin: block in gateway.yaml, the gateway serves an admin API at /v1/organizations/spend_limits. Caps are set through the API, not the YAML. Amounts are whole-number strings of US cents:

1# $500 per month default for every developer2curl -sS https://claude-gateway.internal.example.com/v1/organizations/spend_limits \3  -H "x-api-key: $GATEWAY_ADMIN_WRITE_KEY" \4  -H "Content-Type: application/json" \5  -d '{"scope": {"type": "organization"}, "amount": "50000", "period": "monthly"}'

Scopes are user (by OIDC sub), rbac_group, or organization, and periods are daily, weekly, or monthly. A group or organisation cap is a per-person default, not a shared pool. A developer over any cap gets 429 with error.type: billing_error and a message naming the period and reset time. Claude Code warns them at 75% and 95%.

For capacity, list several upstreams and map each model per upstream. The gateway tries them in order and fails over on 5xx, 429, 401, 403, 404, timeouts, and 501, but not on other 4xx errors:

1upstreams:2  - name: bedrock-east3    provider: bedrock4    region: us-east-15    auth: {}6  - name: bedrock-west7    provider: bedrock8    region: us-west-29    auth: {}10models:11  - id: claude-opus-4-812    upstream_model:13      bedrock-east: us.anthropic.claude-opus-4-814      bedrock-west: us.anthropic.claude-opus-4-8
Spend caps: an effective cap resolves from user override, then group caps, then the organization default, and an over-cap request gets a 429
Spend caps: an effective cap resolves from user override, then group caps, then the organization default, and an over-cap request gets a 429

Quick reference

  • Spend is a USD estimate from list prices (or your pricing.overrides), a circuit breaker rather than an invoice. Model IDs the meter cannot place are charged at $5/$25 per million input/output tokens so they are never free.
  • If Postgres is unreachable, enforcement fails open by default; enforcement.fail_closed_on_error: true blocks instead, trading an outage for no unmetered spend.
  • Aborted streams are still billed with a floor estimate, so cancelling requests early does not evade a cap.
  • The principal_emails table holds email, name, and groups. Delete a person's row directly for offboarding or a data subject access request.

Remember this

Caps are per person, enforced live, and estimated; failover is an ordered list with explicit per-upstream model IDs.

What does not work through the gateway

The gateway trades some first-party features for control. Because Claude Code cannot see which upstream will serve a request, it turns off anything that depends on a specific provider: server-side web search, the one-hour cache TTL, and first-party optimisations such as global cache scope. Remote Control and the design-sync commands need claude.ai, which gateway sessions do not contact. Auto mode works but follows the third-party provider rules for which models are eligible.

Operationally, there is no admin UI and no Helm chart. Configuration is the YAML file under version control, and the gateway runs as a stateless deployment behind your load balancer, with Postgres as its only state.

Selected availability and limitations from Anthropic's gateway docs
FeatureStatusWhy or alternative
Web search toolNot availableThe client cannot verify the upstream supports it, so WebSearch is disabled
Remote ControlNot availableNeeds the Anthropic API
1-hour prompt cache TTLNot availableNot every upstream supports it; caching uses the 5-minute TTL
CI and unattended runsNo service tokensConfigure CI against the provider directly
SAML, LDAPNot supportedOIDC only; front with an OIDC bridge
Multiple OIDC issuersNot supportedRun one gateway per issuer
OTLP over gRPCNot supportedOTLP over HTTP only
Admin UI, Helm chartNot availableEdit the YAML and redeploy; run as a standard Deployment

Quick reference

  • Check the current availability table before rollout; entries change as releases add support.
  • Claude Desktop can route its Cowork and Code tabs (and optionally Chat) through the gateway once a policy opts in with a desktop key.
  • Developers who set a provider variable such as CLAUDE_CODE_USE_BEDROCK bypass the gateway sign-in requirement; block that with managed settings and network rules if it matters.

Remember this

Expect no web search, no Remote Control, a 5-minute cache TTL, and no CI support; plan alternatives before rollout.

Hands-on: a local gateway with your own IdP

Use a test IdP tenant (Keycloak or Dex in a container works) and a test Bedrock or Anthropic API credential.

  1. Register an OIDC client with redirect URI http://localhost:8080/oauth/callback, start Postgres, and write the minimal gateway.yaml with public_url: http://localhost:8080.
  2. Run claude gateway --config gateway.yaml and watch stderr until claude gateway listening on.
  3. Run the three checks: the discovery document, a device authorization, and the browser sign-in.
  4. On the same machine, add forceLoginMethod: "gateway" and forceLoginGatewayUrl to ~/.claude/settings.json (user-settings sign-in needs v2.1.295 or later), run /login, and sign in. Run /model and confirm the picker matches the policy.
  5. Add an eng-contractors policy limited to one model, put your test user in that group, sign in again, and request a different model.

Pass criterion: sign-in completes through your IdP, /model shows only the policy's models, and the request for a non-granted model is refused with 400.

Quick reference

  • Loopback (localhost) is the only host allowed over plain HTTP; anything else needs HTTPS and a private address.
  • If boot exits, the last stderr line names the cause: Postgres unreachable, missing DDL rights, bad OIDC discovery, or a config field path.
  • Read the gateway's audit log for sign-in rejections, such as email domain not allowed.

Remember this

Prove sign-in, the group policy, and a refused model locally before a production deployment.

Key takeaway

The Claude apps gateway is Anthropic's self-hosted gateway for organisations that route Claude through their own cloud. It runs from the claude binary with a gateway.yaml, signs developers in through OIDC with a device flow and a pinned certificate, maps IdP groups to model allowlists and managed settings, enforces per-person spend caps through an admin API, and fails over across upstreams in order. Because it ships with Claude Code, it stays compatible with new request fields without an allowlist.

It is not a fit for everything: there are no service tokens for CI, OIDC is the only identity option, and web search, Remote Control, and the one-hour cache TTL are unavailable. For a gateway you already run, see Claude Code LLM Gateway; for the sandbox and permission rules that apply to the commands Claude runs, see Claude Code Permissions.

Practice (60 min): run the local exercise above, then write the managed.policies list for your own organisation's groups, with a catch-all last.

Share:

References

  1. Claude Code docs: Claude apps gateway — checked Oct 17, 2026
  2. Claude Code docs: Claude apps gateway configuration reference — checked Oct 17, 2026
  3. Claude Code docs: Claude apps gateway spend limits — checked Oct 17, 2026

Shoaib Hossain

Author, Core Concept Learning

Related Articles

When a few engineers use Claude Code, each person's ~/.claude/settings.json is enough. When a company rolls it out to hu…

Read

Many companies already run an LLM gateway, such as LiteLLM, a cloud API gateway, or an in-house proxy, between their dev…

Read

AI coding agents change where engineering effort is spent: the hard problem moves from typing code to defining boundarie…

Read

Keep learning

Follow a structured path or browse all courses to go deeper.