Claude apps gateway for Amazon Bedrock, Claude Platform on AWS, Google Cloud, and Microsoft Foundry changedclaude-apps-gateway
Nearest release: v2.1.304, published 3 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Upstream edited this page at 19 Oct 2026 23:07 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 20 Oct 2026 18:37 UTC.
Upstream edited
Recorded here
Lines+207added
Lines−215removed
From line
2
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits42to this page, all time
### What's enforced on developers
The whole hunk
from line 2, old and new numbered
/
from line 2
22
33> Run Claude Code through Amazon Bedrock, Claude Platform on AWS, Google Cloud, or Microsoft Foundry behind a self-hosted gateway with SSO sign-in, per-group model access, and OTLP telemetry.
44
5<Note>
6 The Claude apps gateway is designed for organizations that must, or prefer to, route inference through their own cloud provider, for example to meet [data residency](/docs/en/claude-apps-gateway-deploy#compliance-posture) requirements. If you don't have this requirement, and want access to other features such as SCIM provisioning or Claude Code on web and mobile, Claude Enterprise may be a better fit. See the [feature availability](/docs/en/feature-availability) page for a full comparison of all deployment methods.
5> [!NOTE]
6>
7> The Claude apps gateway is designed for organizations that must, or prefer to, route inference through their own cloud provider, for example to meet [data residency](/docs/en/claude-apps-gateway-deploy#compliance-posture) requirements. If you don't have this requirement, and want access to other features such as SCIM provisioning or Claude Code on web and mobile, Claude Enterprise may be a better fit. See the [feature availability](/docs/en/feature-availability) page for a full comparison of all deployment methods.
8>
9> Claude Code uses one sign-in at a time: a gateway sign-in takes the place of a Claude for Teams or Enterprise login. Gateway sessions don't fetch the [server-managed settings](/docs/en/server-managed-settings) you set in the claude.ai admin console, so deliver them from the gateway's [`managed` block](/docs/en/claude-apps-gateway-config#managed). Leave `forceLoginMethod` and `forceLoginOrgUUID` out of that block, or [some signed-in sessions exit at startup](/docs/en/claude-apps-gateway-config#client-side-managed-settings). See [Availability and limitations](#availability-and-limitations) for what gateway sessions lose.
710
8 Claude Code uses one sign-in at a time: a gateway sign-in takes the place of a Claude for Teams or Enterprise login. Gateway sessions don't fetch the [server-managed settings](/docs/en/server-managed-settings) you set in the claude.ai admin console, so deliver them from the gateway's [`managed` block](/docs/en/claude-apps-gateway-config#managed). Leave `forceLoginMethod` and `forceLoginOrgUUID` out of that block, or [some signed-in sessions exit at startup](/docs/en/claude-apps-gateway-config#client-side-managed-settings). See [Availability and limitations](#availability-and-limitations) for what gateway sessions lose.
9</Note>
10
1111Claude apps gateway is a self-hosted service that sits between your developers' Claude Code clients and your model provider. Developers sign in with your corporate identity provider (IdP) instead of holding API keys or cloud credentials. The gateway holds the upstream credential, enforces model access and [managed settings](/docs/en/managed-settings) by IdP group, and relays usage telemetry to your own observability stack.
1212
1313It is included in the `claude` binary, so the same executable that runs Claude Code on a laptop runs the gateway server with `claude gateway --config gateway.yaml`.
from line 31
3131* **Telemetry**: each configured destination receives [OpenTelemetry Protocol (OTLP) metrics](/docs/en/monitoring-usage) with token counts, model, user identity, and latency by default, with logs and traces as per-destination opt-ins.
3232* **Upstream routing**: clients speak the Anthropic Messages API to the gateway, and the gateway translates for each upstream, whether Amazon Bedrock, [Claude Platform on AWS](/docs/en/claude-platform-on-aws), Google Cloud's Agent Platform, Microsoft Foundry, or the Anthropic API, with failover between them. You can change regions, providers, or failover order without developers noticing or reconfiguring.
3333
34<Frame>
35 <img src="https://mintcdn.com/claude-code/VbyXug8hBU9UK6oT/images/claude-gateway-architecture.svg?fit=max&auto=format&n=VbyXug8hBU9UK6oT&q=85&s=9e4f1190fc56718144190a3db61c63af" alt="Diagram showing Claude Code clients and Claude Desktop's Chat, Cowork, and Code tabs connecting over HTTPS with bearer tokens to a self-hosted Claude apps gateway inside your infrastructure, which signs users in against your IdP, stores auth state in PostgreSQL, relays telemetry to your OTLP collector, and forwards inference to Amazon Bedrock, Claude Platform on AWS, Google Cloud, Microsoft Foundry, or the Anthropic API" width="760" height="320" data-path="images/claude-gateway-architecture.svg" />
36</Frame>
34
3735
38<Note>
39 The gateway's own data plane sends nothing to Anthropic infrastructure unless the Anthropic API is a configured upstream. You control where telemetry, audit logs, managed settings, and your developers' IdP identity go, and the gateway sends none of them to Anthropic. For the remaining traffic the CLI process can send and how to close it, see [Compliance posture](/docs/en/claude-apps-gateway-deploy#compliance-posture).
40</Note>
36> [!NOTE]
37>
38> The gateway's own data plane sends nothing to Anthropic infrastructure unless the Anthropic API is a configured upstream. You control where telemetry, audit logs, managed settings, and your developers' IdP identity go, and the gateway sends none of them to Anthropic. For the remaining traffic the CLI process can send and how to close it, see [Compliance posture](/docs/en/claude-apps-gateway-deploy#compliance-posture).
4139
4240For which Claude Code features work through the gateway and what the server itself supports, see [Availability and limitations](#availability-and-limitations) below. For decisions such as cost, bypass, running multiple gateways, and serverless platforms, see the [deployment guide](/docs/en/claude-apps-gateway-deploy#deployment).
4341
from line 47
4947
5048Breaking changes to the protocol are announced in advance, but indefinite backwards compatibility isn't guaranteed.
5149
52<Note>
53 A gateway sign-in token identifies the developer who approved the sign-in, not the program that uses it. Claude Code signs in without a client ID or secret of its own, so a gateway has no way to verify which program is signing in. Any client can set `User-Agent` and other request fields, so use them for routing or metrics, not as proof that a request comes from Claude Code.
54</Note>
50> [!NOTE]
51>
52> A gateway sign-in token identifies the developer who approved the sign-in, not the program that uses it. Claude Code signs in without a client ID or secret of its own, so a gateway has no way to verify which program is signing in. Any client can set `User-Agent` and other request fields, so use them for routing or metrics, not as proof that a request comes from Claude Code.
5553
5654## Quickstart
5755
5856This quickstart walks the minimal path: register an OAuth client in your IdP, write a `gateway.yaml`, run the gateway alongside Postgres with Docker Compose, and verify sign-in end to end. It uses an Amazon Bedrock upstream; Claude Platform on AWS, Google Cloud's Agent Platform, Microsoft Foundry, and the Anthropic API are equally supported by swapping the `upstreams` block as shown in the [configuration reference](/docs/en/claude-apps-gateway-config#upstreams). At the end you have a gateway a developer can `/login` to.
5957
60<Note>
61 **Deploy on your private network.** Claude Code only connects to a gateway whose address is private. This is a security guard, because a trusted gateway can push settings that run commands on developer machines. Put the gateway behind an internal load balancer or VPN and give it a hostname that resolves to private IPs only. If your internal network is numbered from public IPv4 space your organization owns, see [Allow a gateway on public address space you own](#allow-a-gateway-on-public-address-space-you-own).
62</Note>
58> [!NOTE]
59>
60> **Deploy on your private network.** Claude Code only connects to a gateway whose address is private. This is a security guard, because a trusted gateway can push settings that run commands on developer machines. Put the gateway behind an internal load balancer or VPN and give it a hostname that resolves to private IPs only. If your internal network is numbered from public IPv4 space your organization owns, see [Allow a gateway on public address space you own](#allow-a-gateway-on-public-address-space-you-own).
6361
6462### Prerequisites
6563
from line 75
7775
7876### Steps
7977
80<Steps>
81 <Step title="Register an OAuth client in your IdP">
82 Decide the gateway's hostname first, because the redirect URI must match it. Create a new OIDC web application and set the redirect URI to `https://claude-gateway.<your-domain>/oauth/callback`, where the host is the same value you set as [`listen.public_url`](/docs/en/claude-apps-gateway-config#listen) in step 3. Note the `client_id` and `client_secret`. Per-IdP instructions are in [Identity provider setup](/docs/en/claude-apps-gateway-deploy#identity-provider-setup).
83 </Step>
78**1. Register an OAuth client in your IdP**
8479
85 <Step title="Provision a PostgreSQL database">
86 Use PostgreSQL 11 or later. The smallest managed tier is enough. The gateway runs its own schema migrations at boot, so the database role needs rights to create and alter tables; see [`store`](/docs/en/claude-apps-gateway-config#store).
87 </Step>
80Decide the gateway's hostname first, because the redirect URI must match it. Create a new OIDC web application and set the redirect URI to `https://claude-gateway.<your-domain>/oauth/callback`, where the host is the same value you set as [`listen.public_url`](/docs/en/claude-apps-gateway-config#listen) in step 3. Note the `client_id` and `client_secret`. Per-IdP instructions are in [Identity provider setup](/docs/en/claude-apps-gateway-deploy#identity-provider-setup).
8881
89 <Step title="Write gateway.yaml">
90 Secrets are read via `${ENV_VAR}` expansion so the file itself can live in version control. Use a `public_url` hostname that resolves to a private IP on your network, because `/login` rejects public addresses. The minimal config has five sections, and every other field has a default:
82**2. Provision a PostgreSQL database**
9183
92 ```yaml gateway.yaml theme={null}
93 listen:
94 host: 0.0.0.0
95 port: 8080
96 # Required unless host is a loopback address. Used for the IdP
97 # redirect_uri and the discovery document.
98 public_url: https://claude-gateway.internal.example.com
84Use PostgreSQL 11 or later. The smallest managed tier is enough. The gateway runs its own schema migrations at boot, so the database role needs rights to create and alter tables; see [`store`](/docs/en/claude-apps-gateway-config#store).
9985
100 oidc:
101 issuer: https://login.example.com # must serve /.well-known/openid-configuration
102 client_id: 0oa1example2
103 client_secret: ${OIDC_CLIENT_SECRET}
104 allowed_email_domains: [example.com] # reject id_tokens outside your org
105 userinfo_fallback: true # for IdPs whose id_token omits email/groups; harmless otherwise
86**3. Write gateway.yaml**
10687
107 session:
108 jwt_secret: ${GATEWAY_JWT_SECRET} # openssl rand -base64 32
109 ttl_hours: 1 # also bounds revocation latency on IdP deprovision
88Secrets are read via `${ENV_VAR}` expansion so the file itself can live in version control. Use a `public_url` hostname that resolves to a private IP on your network, because `/login` rejects public addresses. The minimal config has five sections, and every other field has a default:
11089
111 store:
112 postgres_url: ${GATEWAY_POSTGRES_URL} # add ?sslmode=require for managed Postgres
90```yaml gateway.yaml theme={null}
91listen:
92 host: 0.0.0.0
93 port: 8080
94 # Required unless host is a loopback address. Used for the IdP
95 # redirect_uri and the discovery document.
96 public_url: https://claude-gateway.internal.example.com
11397
114 upstreams:
115 - provider: bedrock
116 region: us-east-1
117 auth: {} # empty: AWS default credential chain
118 # (IRSA, EC2/ECS task role, env vars, ~/.aws)
98oidc:
99 issuer: https://login.example.com # must serve /.well-known/openid-configuration
100 client_id: 0oa1example2
101 client_secret: ${OIDC_CLIENT_SECRET}
102 allowed_email_domains: [example.com] # reject id_tokens outside your org
103 userinfo_fallback: true # for IdPs whose id_token omits email/groups; harmless otherwise
119104
120 # Models are translated per upstream automatically. The built-in catalog
121 # maps claude-opus-4-8 to us.anthropic.claude-opus-4-8 and so on for every
122 # Bedrock-supported Claude model. Set false and add a `models:` list to
123 # expose only specific models.
124 auto_include_builtin_models: true
125 ```
105session:
106 jwt_secret: ${GATEWAY_JWT_SECRET} # openssl rand -base64 32
107 ttl_hours: 1 # also bounds revocation latency on IdP deprovision
126108
127 This config is enough for a working sign-in loop with the default Amazon Bedrock model catalog. Once it's running, add per-group RBAC and managed settings via [`managed.policies`](/docs/en/claude-apps-gateway-config#managed), telemetry fan-out via [`telemetry`](/docs/en/claude-apps-gateway-config#telemetry), and multi-upstream failover, provisioned-throughput ARNs, or non-US regions via [`models`](/docs/en/claude-apps-gateway-config#models).
109store:
110 postgres_url: ${GATEWAY_POSTGRES_URL} # add ?sslmode=require for managed Postgres
128111
129 <Note>
130 The Amazon Bedrock upstream needs an AWS principal with `bedrock:InvokeModel` and `bedrock:InvokeModelWithResponseStream` on both the `inference-profile/us.anthropic.*` ARNs and the underlying `foundation-model/anthropic.*` ARNs. It also needs Anthropic's one-time use case form submitted for the account from the Bedrock console's Model catalog.
112upstreams:
113 - provider: bedrock
114 region: us-east-1
115 auth: {} # empty: AWS default credential chain
116 # (IRSA, EC2/ECS task role, env vars, ~/.aws)
131117
132 Supply the credential with IRSA on EKS, an ECS task role, or an EC2 instance profile rather than static keys. The [`upstreams` reference](/docs/en/claude-apps-gateway-config#upstreams) has the full IAM details, the cross-cloud credential matrix, and the `auth` blocks for the other providers.
133 </Note>
134 </Step>
118# Models are translated per upstream automatically. The built-in catalog
119# maps claude-opus-4-8 to us.anthropic.claude-opus-4-8 and so on for every
120# Bedrock-supported Claude model. Set false and add a `models:` list to
121# expose only specific models.
122auto_include_builtin_models: true
123```
135124
136 <Step title="Run it">
137 Build a container image around the `claude` binary that meets the [image requirements](/docs/en/claude-apps-gateway-deploy#container-image), then run it alongside Postgres. The Compose file references the image as `registry.example.com/claude-gateway:2.1.198`; substitute your own registry and image tag:
125This config is enough for a working sign-in loop with the default Amazon Bedrock model catalog. Once it's running, add per-group RBAC and managed settings via [`managed.policies`](/docs/en/claude-apps-gateway-config#managed), telemetry fan-out via [`telemetry`](/docs/en/claude-apps-gateway-config#telemetry), and multi-upstream failover, provisioned-throughput ARNs, or non-US regions via [`models`](/docs/en/claude-apps-gateway-config#models).
138126
139 ```yaml docker-compose.yaml theme={null}
140 services:
141 gateway:
142 image: registry.example.com/claude-gateway:2.1.198
143 ports: ["8080:8080"]
144 volumes: ["./gateway.yaml:/etc/claude/gateway.yaml:ro"]
145 environment:
146 OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET}
147 GATEWAY_JWT_SECRET: ${GATEWAY_JWT_SECRET}
148 GATEWAY_POSTGRES_URL: postgres://gw:pw@postgres/gateway
149 # AWS credentials: in production, omit these and use an instance
150 # role. For local Compose testing, pass through your own:
151 AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
152 AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
153 AWS_SESSION_TOKEN: ${AWS_SESSION_TOKEN}
154 depends_on:
155 postgres:
156 condition: service_healthy
127> [!NOTE]
128>
129> The Amazon Bedrock upstream needs an AWS principal with `bedrock:InvokeModel` and `bedrock:InvokeModelWithResponseStream` on both the `inference-profile/us.anthropic.*` ARNs and the underlying `foundation-model/anthropic.*` ARNs. It also needs Anthropic's one-time use case form submitted for the account from the Bedrock console's Model catalog.
130>
131> Supply the credential with IRSA on EKS, an ECS task role, or an EC2 instance profile rather than static keys. The [`upstreams` reference](/docs/en/claude-apps-gateway-config#upstreams) has the full IAM details, the cross-cloud credential matrix, and the `auth` blocks for the other providers.
132
133**4. Run it**
134
135Build a container image around the `claude` binary that meets the [image requirements](/docs/en/claude-apps-gateway-deploy#container-image), then run it alongside Postgres. The Compose file references the image as `registry.example.com/claude-gateway:2.1.198`; substitute your own registry and image tag:
136
137```yaml docker-compose.yaml theme={null}
138services:
139 gateway:
140 image: registry.example.com/claude-gateway:2.1.198
141 ports: ["8080:8080"]
142 volumes: ["./gateway.yaml:/etc/claude/gateway.yaml:ro"]
143 environment:
144 OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET}
145 GATEWAY_JWT_SECRET: ${GATEWAY_JWT_SECRET}
146 GATEWAY_POSTGRES_URL: postgres://gw:pw@postgres/gateway
147 # AWS credentials: in production, omit these and use an instance
148 # role. For local Compose testing, pass through your own:
149 AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
150 AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
151 AWS_SESSION_TOKEN: ${AWS_SESSION_TOKEN}
152 depends_on:
157153 postgres:
158 image: postgres:16-alpine
159 environment: { POSTGRES_USER: gw, POSTGRES_PASSWORD: pw, POSTGRES_DB: gateway }
160 healthcheck:
161 test: ["CMD-SHELL", "pg_isready -U gw"]
162 interval: 5s
163 volumes: ["pgdata:/var/lib/postgresql/data"]
164 volumes: { pgdata: }
165 ```
154 condition: service_healthy
155 postgres:
156 image: postgres:16-alpine
157 environment: { POSTGRES_USER: gw, POSTGRES_PASSWORD: pw, POSTGRES_DB: gateway }
158 healthcheck:
159 test: ["CMD-SHELL", "pg_isready -U gw"]
160 interval: 5s
161 volumes: ["pgdata:/var/lib/postgresql/data"]
162volumes: { pgdata: }
163```
166164
167 The gateway is a single Linux binary that reads the config, connects to Postgres and applies its schema migrations, runs OIDC discovery against your IdP, builds upstream clients, and starts listening.
165The gateway is a single Linux binary that reads the config, connects to Postgres and applies its schema migrations, runs OIDC discovery against your IdP, builds upstream clients, and starts listening.
168166
169 Boot is fail-closed for the config, the Postgres connection, OIDC discovery, and upstream client construction. If any of those is unreachable or misconfigured, the gateway exits with an error rather than serving traffic in a degraded state.
167Boot is fail-closed for the config, the Postgres connection, OIDC discovery, and upstream client construction. If any of those is unreachable or misconfigured, the gateway exits with an error rather than serving traffic in a degraded state.
170168
171 A successful boot doesn't validate the inference path, because Amazon Bedrock and Google Cloud's Agent Platform instance credentials resolve on the first request, not at boot.
169A successful boot doesn't validate the inference path, because Amazon Bedrock and Google Cloud's Agent Platform instance credentials resolve on the first request, not at boot.
172170
173 Watch stderr for the boot sequence. Log lines use the format `[gateway] <timestamp> <level> <message>`, audit events are single-line JSON with an `evt` field, and a startup banner, omitted below, prints between the migration and listening lines. A fresh database prints one `migration N applied` line per schema migration; an already-migrated database prints none. You should see, in order:
171Watch stderr for the boot sequence. Log lines use the format `[gateway] <timestamp> <level> <message>`, audit events are single-line JSON with an `evt` field, and a startup banner, omitted below, prints between the migration and listening lines. A fresh database prints one `migration N applied` line per schema migration; an already-migrated database prints none. You should see, in order:
174172
175 ```text theme={null}
176 {"ts":"2026-06-10T17:03:21.114Z","evt":"config.load","path":"/etc/claude/gateway.yaml","sha256":"…"}
177 [gateway] 2026-06-10T17:03:21.395Z info waiting for migration lock (another replica may be migrating; check pg_locks for key 6775156 if this persists)
178 [gateway] 2026-06-10T17:03:21.408Z info migration 1 applied
179 …
180 [gateway] 2026-06-10T17:03:21.431Z info migration 6 applied
181 [gateway] 2026-06-10T17:03:21.512Z info claude gateway listening on http://0.0.0.0:8080
182 ```
173```text theme={null}
174{"ts":"2026-06-10T17:03:21.114Z","evt":"config.load","path":"/etc/claude/gateway.yaml","sha256":"…"}
175[gateway] 2026-06-10T17:03:21.395Z info waiting for migration lock (another replica may be migrating; check pg_locks for key 6775156 if this persists)
176[gateway] 2026-06-10T17:03:21.408Z info migration 1 applied
177…
178[gateway] 2026-06-10T17:03:21.431Z info migration 6 applied
179[gateway] 2026-06-10T17:03:21.512Z info claude gateway listening on http://0.0.0.0:8080
180```
183181
184 The gateway also logs a warning that `access_control.allow_cidrs` is empty. That's expected here, because nothing limits which client addresses the gateway serves until you set an allow list. The [`access_control` reference](/docs/en/claude-apps-gateway-config#http-tuning) has the recommended ranges.
182The gateway also logs a warning that `access_control.allow_cidrs` is empty. That's expected here, because nothing limits which client addresses the gateway serves until you set an allow list. The [`access_control` reference](/docs/en/claude-apps-gateway-config#http-tuning) has the recommended ranges.
185183
186 If boot exits before the `claude gateway listening on` line, the last line of stderr names the problem:
184If boot exits before the `claude gateway listening on` line, the last line of stderr names the problem:
187185
188 * an unreachable Postgres
189 * a Postgres role without DDL permission
190 * an unreachable or invalid OIDC discovery document
191 * a config schema violation with the offending field path
186* an unreachable Postgres
187* a Postgres role without DDL permission
188* an unreachable or invalid OIDC discovery document
189* a config schema violation with the offending field path
192190
193 Fix it and restart.
191Fix it and restart.
194192
195 If you already have a TLS-terminating ingress, skip Compose and run the binary directly with `claude gateway --config gateway.yaml`. Set `public_url` to the ingress origin and bind `listen` to a loopback or cluster-internal address.
196 </Step>
193If you already have a TLS-terminating ingress, skip Compose and run the binary directly with `claude gateway --config gateway.yaml`. Set `public_url` to the ingress origin and bind `listen` to a loopback or cluster-internal address.
197194
198 <Step title="Verify the auth surface">
199 Three checks confirm the gateway can authenticate a real user before you share it with a developer.
195**5. Verify the auth surface**
200196
201 The examples use the gateway's public URL; for the local Compose setup without an ingress, substitute `http://localhost:8080` in the first two checks. The third check opens `verification_uri_complete`, which is built from `public_url`, so for local Compose set `public_url: http://localhost:8080` in `gateway.yaml`, and add `http://localhost:8080/oauth/callback` as a second redirect URI on the OAuth client from step 1, because the gateway builds the IdP `redirect_uri` from `public_url`. The verification link then opens in your local browser.
197Three checks confirm the gateway can authenticate a real user before you share it with a developer.
202198
203 In Windows PowerShell, run `curl.exe`; the bare `curl` is an alias for `Invoke-WebRequest` and rejects these flags.
199The examples use the gateway's public URL; for the local Compose setup without an ingress, substitute `http://localhost:8080` in the first two checks. The third check opens `verification_uri_complete`, which is built from `public_url`, so for local Compose set `public_url: http://localhost:8080` in `gateway.yaml`, and add `http://localhost:8080/oauth/callback` as a second redirect URI on the OAuth client from step 1, because the gateway builds the IdP `redirect_uri` from `public_url`. The verification link then opens in your local browser.
204200
205 First, fetch the discovery document, which confirms the gateway is up, the config is valid, and all boot checks passed:
201In Windows PowerShell, run `curl.exe`; the bare `curl` is an alias for `Invoke-WebRequest` and rejects these flags.
206202
207 ```bash theme={null}
208 curl -s https://claude-gateway.internal.example.com/.well-known/oauth-authorization-server | jq
209 ```
203First, fetch the discovery document, which confirms the gateway is up, the config is valid, and all boot checks passed:
210204
211 ```json theme={null}
212 {
213 "issuer": "https://claude-gateway.internal.example.com",
214 "device_authorization_endpoint": "…/oauth/device_authorization",
215 "token_endpoint": "…/oauth/token",
216 "grant_types_supported": ["urn:ietf:params:oauth:grant-type:device_code", "refresh_token"]
217 }
218 ```
205```bash theme={null}
206curl -s https://claude-gateway.internal.example.com/.well-known/oauth-authorization-server | jq
207```
219208
220 The response includes additional fields, such as `response_types_supported` and `scopes_supported`.
209```json theme={null}
210{
211 "issuer": "https://claude-gateway.internal.example.com",
212 "device_authorization_endpoint": "…/oauth/device_authorization",
213 "token_endpoint": "…/oauth/token",
214 "grant_types_supported": ["urn:ietf:params:oauth:grant-type:device_code", "refresh_token"]
215}
216```
221217
222 Second, request a device authorization, which confirms the device sign-in flow works and Postgres is reachable and writable:
218The response includes additional fields, such as `response_types_supported` and `scopes_supported`.
223219
224 ```bash theme={null}
225 curl -s -X POST https://claude-gateway.internal.example.com/oauth/device_authorization | jq
226 ```
220Second, request a device authorization, which confirms the device sign-in flow works and Postgres is reachable and writable:
227221
228 ```json theme={null}
229 {
230 "device_code": "…",
231 "user_code": "WDJB-MJHT",
232 "verification_uri": "https://claude-gateway.internal.example.com/device",
233 "verification_uri_complete": "https://claude-gateway.internal.example.com/device?user_code=WDJB-MJHT",
234 "expires_in": 600,
235 "interval": 5
236 }
237 ```
222```bash theme={null}
223curl -s -X POST https://claude-gateway.internal.example.com/oauth/device_authorization | jq
224```
238225
239 Third, test the browser leg by opening `verification_uri_complete` in a browser and confirming the code. You should be redirected to your IdP's sign-in page, and after signing in, land back on the gateway with a signed-in confirmation.
226```json theme={null}
227{
228 "device_code": "…",
229 "user_code": "WDJB-MJHT",
230 "verification_uri": "https://claude-gateway.internal.example.com/device",
231 "verification_uri_complete": "https://claude-gateway.internal.example.com/device?user_code=WDJB-MJHT",
232 "expires_in": 600,
233 "interval": 5
234}
235```
240236
241 Use the first failing check to locate the problem:
237Third, test the browser leg by opening `verification_uri_complete` in a browser and confirming the code. You should be redirected to your IdP's sign-in page, and after signing in, land back on the gateway with a signed-in confirmation.
242238
243 * **First check fails**: boot didn't complete; check stderr
244 * **Second check fails**: Postgres isn't reachable from the gateway or the role can't write; check the connection string and grants
245 * **Third check doesn't reach the IdP**: check that the IdP's redirect URI matches `https://<gateway>/oauth/callback` exactly
246 * **Third check reaches the IdP but bounces back with an error**: read the gateway's audit log, which records every auth rejection with the reason, such as `email domain not allowed`
247 </Step>
239Use the first failing check to locate the problem:
248240
249 <Step title="Log a developer in">
250 This last step happens on a developer machine, not the server. Set `forceLoginMethod` to `"gateway"`, `forceLoginGatewayUrl` to your gateway's `public_url`, and `parentSettingsBehavior` to `"merge"` in that machine's [managed settings file](/docs/en/managed-settings#delivery-mechanisms), then run `/login`, press Enter on the **Cloud gateway** screen, and complete the browser sign-in. [Set the gateway URL](#set-the-gateway-url) below covers the three keys and distributing them to every developer machine.
251 </Step>
252</Steps>
241* **First check fails**: boot didn't complete; check stderr
242* **Second check fails**: Postgres isn't reachable from the gateway or the role can't write; check the connection string and grants
243* **Third check doesn't reach the IdP**: check that the IdP's redirect URI matches `https://<gateway>/oauth/callback` exactly
244* **Third check reaches the IdP but bounces back with an error**: read the gateway's audit log, which records every auth rejection with the reason, such as `email domain not allowed`
253245
246**6. Log a developer in**
247
248This last step happens on a developer machine, not the server. Set `forceLoginMethod` to `"gateway"`, `forceLoginGatewayUrl` to your gateway's `public_url`, and `parentSettingsBehavior` to `"merge"` in that machine's [managed settings file](/docs/en/managed-settings#delivery-mechanisms), then run `/login`, press Enter on the **Cloud gateway** screen, and complete the browser sign-in. [Set the gateway URL](#set-the-gateway-url) below covers the three keys and distributing them to every developer machine.
249
254250## Connect developers
255251
256252Developers connect from their own laptops with one browser sign-in, using their corporate work account. They don't need a claude.ai account, an API key, or a subscription, because requests to the model go through the gateway using the organization's upstream credential. Connection is driven by the [client-side managed settings](/docs/en/claude-apps-gateway-config#client-side-managed-settings) you push via MDM, and this section covers what the admin configures.
from line 305
309305
310306Some organizations number their internal network from a public IPv4 block they own, such as a carrier's own address space or a legacy `/8`, so their gateway has no private address. List those blocks in the `gatewayInternalNetworks` managed setting. `/login` then accepts a gateway inside a listed block when the developer's machine connects to it from an address inside the same block. This requires Claude Code v2.1.268 or later on the developer machine; earlier versions ignore the key and apply the private-address rule.
311307
312<Warning>
313 `gatewayInternalNetworks` is for internal networks that happen to be numbered from public address space. It doesn't make it safe to expose a gateway to the internet: a trusted gateway can push settings that run commands on developer machines.
308> [!WARNING]
309>
310> `gatewayInternalNetworks` is for internal networks that happen to be numbered from public address space. It doesn't make it safe to expose a gateway to the internet: a trusted gateway can push settings that run commands on developer machines.
311>
312> Keep the gateway unreachable from outside your network with your firewall or load balancer rules. Set the gateway's [`access_control.allow_cidrs`](/docs/en/claude-apps-gateway-config#http-tuning) to the same blocks you declare here, so the gateway itself refuses clients from anywhere else. Behind a load balancer or ingress, set `listen.trusted_proxies` to that front end as well, because the gateway otherwise matches `allow_cidrs` against the front end's own address rather than the developer's.
314313
315 Keep the gateway unreachable from outside your network with your firewall or load balancer rules. Set the gateway's [`access_control.allow_cidrs`](/docs/en/claude-apps-gateway-config#http-tuning) to the same blocks you declare here, so the gateway itself refuses clients from anywhere else. Behind a load balancer or ingress, set `listen.trusted_proxies` to that front end as well, because the gateway otherwise matches `allow_cidrs` against the front end's own address rather than the developer's.
316</Warning>
317
318314Add the key to the same managed settings source as the login keys: the managed settings file, MDM profile, or registry policy. Claude Code ignores it in user, project, and server-managed settings.
319315
320316This example declares one block. Replace `203.0.113.0/24` with your own block. It is a documentation range, and Claude Code refuses those.
from line 366
370366
371367Deploy the managed settings snippet from [Set the gateway URL](#set-the-gateway-url), mirror it to any client-side source that outranks the file, then verify.
372368
373<Steps>
374 <Step title="Deploy the opt-in in the managed settings file">
375 The [snippet above](#set-the-gateway-url) already includes `parentSettingsBehavior: "merge"`, so the file you push to machines carries it.
376 </Step>
369**1. Deploy the opt-in in the managed settings file**
377370
378 <Step title="Mirror the snippet to any source that outranks the file">
379 Claude Code reads `parentSettingsBehavior` only from the [selected source](/docs/en/managed-settings#which-managed-source-claude-code-uses). Adding any policy key to a source can make that source the selected one, so in a client-side source, mirror the whole snippet rather than `parentSettingsBehavior` alone. [Client-side managed settings](/docs/en/claude-apps-gateway-config#client-side-managed-settings) covers fleets that deliver policy through Group Policy or configuration profiles. A managed-preferences plist on macOS or an HKLM policy on Windows outranks the `managed-settings.json` file, and the gateway's own remote managed settings outrank both, so on machines that sign in to the gateway, also set `parentSettingsBehavior` in the gateway policy's [`cli` or `code` block](/docs/en/claude-apps-gateway-config#managed).
380 </Step>
371The [snippet above](#set-the-gateway-url) already includes `parentSettingsBehavior: "merge"`, so the file you push to machines carries it.
381372
382 <Step title="Check which source is selected">
383 On a machine that only runs Claude Desktop, call the Agent SDK's [`resolveSettings()`](/docs/en/agent-sdk/typescript#resolvesettings) and read `policyOrigin` on the `managed` entry in its `sources` list. The value names the selected client-side source, `plist`, `hklm`, or `file`, which is the source that must carry the snippet.
373**2. Mirror the snippet to any source that outranks the file**
384374
385 Cowork and Chat sessions don't fetch the gateway policy, so the gateway's block isn't the selected source for them.
375Claude Code reads `parentSettingsBehavior` only from the [selected source](/docs/en/managed-settings#which-managed-source-claude-code-uses). Adding any policy key to a source can make that source the selected one, so in a client-side source, mirror the whole snippet rather than `parentSettingsBehavior` alone. [Client-side managed settings](/docs/en/claude-apps-gateway-config#client-side-managed-settings) covers fleets that deliver policy through Group Policy or configuration profiles. A managed-preferences plist on macOS or an HKLM policy on Windows outranks the `managed-settings.json` file, and the gateway's own remote managed settings outrank both, so on machines that sign in to the gateway, also set `parentSettingsBehavior` in the gateway policy's [`cli` or `code` block](/docs/en/claude-apps-gateway-config#managed).
386376
387 A Code tab session fetches it when the policy's settings are under `code` and the [conditions for the Code tab](/docs/en/claude-apps-gateway-config#apply-code-settings-in-the-code-tab) hold. The gateway's `code` settings are then the selected source for that session.
388 </Step>
389</Steps>
377**3. Check which source is selected**
390378
379On a machine that only runs Claude Desktop, call the Agent SDK's [`resolveSettings()`](/docs/en/agent-sdk/typescript#resolvesettings) and read `policyOrigin` on the `managed` entry in its `sources` list. The value names the selected client-side source, `plist`, `hklm`, or `file`, which is the source that must carry the snippet.
380
381Cowork and Chat sessions don't fetch the gateway policy, so the gateway's block isn't the selected source for them.
382
383A Code tab session fetches it when the policy's settings are under `code` and the [conditions for the Code tab](/docs/en/claude-apps-gateway-config#apply-code-settings-in-the-code-tab) hold. The gateway's `code` settings are then the selected source for that session.
384
391385### Restrict parent settings
392386
393387Once you deploy `parentSettingsBehavior: "merge"`, any host process that launches Claude Code can supply parent settings, not only Claude Desktop but also an Agent SDK application or an IDE extension.
from line 468
474468
475469The device flow separates the polling CLI from the approving browser, so a remote development box with no display still works: the developer runs `/login` over SSH on the remote machine and opens the verification link in the browser on their laptop.
476470
477<h3 id="whats-enforced-on-developers">
478 What's enforced on developers
479</h3>
471### What's enforced on developers
480472
481473These guarantees apply to every session signed in through `/login`. The embedded sessions Claude Desktop launches get their policy as described in [Deliver policy to Claude Desktop sessions](#deliver-policy-to-claude-desktop-sessions), and the telemetry bullet says where their exports go.
482474
No line in this hunk matches that.