What this read moved
1–8 of 8claude-tag/admins/federated-access/authorization-server New page · 137 lines, new page
# Connect an authorization server ## Before you begin ## Copy the values from the console ## Configure the authorization server ## Register the endpoint and connect the server ## Let agents use the APIs ## Verify the connection ## Remove the server ## Common errors ## Related resources
A whole new page. There's nothing to diff it against, so here is what it says.
# Connect an authorization server
> Let Claude exchange a short-lived identity token for an access token from an OAuth 2.0 authorization server you run, then call your APIs with it. Covers what your token endpoint receives and must check, what it returns, and how to register it in the console.
export const BetaNote = () => <Info>Claude Tag is in public beta. Features and behavior described here may change before general availability.</Info>;
<BetaNote />
<Note>Authorization servers are connected at [`claude.ai/admin-settings/claude-tag`](https://claude.ai/admin-settings/claude-tag): open **Federated cloud access** in the left navigation and use the **Authorization servers** section. Connecting a server needs an organization Owner, or an admin with full Claude Tag management permission.</Note>
With an authorization server connection, Claude presents a short-lived identity token to an OAuth 2.0 authorization server you run, receives one of your access tokens in return, and calls your APIs with it. No long-lived credential for your systems is stored in Claude, and [Agent Proxy](/docs/claude-tag/concepts/agent-identity#agent-proxy) holds each access token only until it expires. The identity token names your organization and the [agent](/docs/claude-tag/concepts/agent-identity) making the request (Claude's identity in one Slack channel), and your server decides whether to issue a token for it.
Choose this when you run an authorization server that issues tokens for your APIs. If your own service will verify the identity token on every request instead, [connect a gateway](/docs/claude-tag/admins/federated-access/connect-a-gateway). If a vendor's API gave you a private key to sign assertions with (Salesforce, for example), use the [OAuth 2.0 JWT bearer](/docs/claude-tag/admins/connections/custom#oauth-2-0-jwt-bearer) credential type instead; the console labels this page's connection **Authorization server**.
Two terms recur on this page. The **subject check** is what your server does to every identity token, confirming it belongs to your organization. The **connection check** is the probe the console runs when a gateway is connected; it doesn't run for token endpoints.
## Before you begin
* You're an organization Owner, or an admin with full Claude Tag management permission.
* Your authorization server's token endpoint is reachable from the internet over HTTPS at an address with a domain name, such as `https://auth.example.com/oauth2/token`. The console accepts an address that:
* is at most 256 characters
* may have a path, with no spaces or special characters in it
* has no port number (the console drops `:443`), query, fragment, or sign-in details
* isn't an IP address, a private-network name, an Anthropic-owned host, or a cloud token-exchange host
* The token endpoint is on a different host from the APIs Claude will call with the returned token, for example `auth.example.com` and `api.example.com`.
* Your server can reach `https://identity.anthropic.com` to fetch Anthropic's signing keys.
* An organization can register up to 5 [gateways](/docs/claude-tag/admins/federated-access/connect-a-gateway), and a token endpoint counts as one.
## Copy the values from the console
In **Authorization servers**, click **Connect an authorization server**, enter your token endpoint in the **Token endpoint** field, enter your authorization server's issuer identifier in the **Issuer URL** field (or leave it empty if your server requires the token endpoint URL as the audience), and copy the **Issuer**, **JWKS URL**, **Audience**, and **Subject prefix** rows from the **Set your authorization server to accept these values** card. Then click **Cancel**; you register the endpoint after configuring the server.
| Value | What to configure |
| :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Issuer | `https://identity.anthropic.com/agents`, matched exactly. The OpenID Connect (OIDC) discovery document is at `https://identity.anthropic.com/agents/.well-known/openid-configuration`. |
| JWKS URL | The JSON Web Key Set (JWKS) named by `jwks_uri` in the discovery document, `https://identity.anthropic.com/agents/jwks.json`. Accept ES256 only. Select the key by `kid`, and refetch the JWKS on an unknown `kid` before rejecting the token. |
| Audience | Your authorization server's issuer identifier, as you enter it in the **Issuer URL** field when you connect the server, for example `https://auth.example.com`. It must be an HTTPS URL on the same host as the token endpoint. If your server requires the token endpoint URL as the audience instead, leave **Issuer URL** empty and the audience is the token endpoint address as the console stores it (the host lowercased, a bare trailing slash dropped, the rest kept as entered). Either way, copy the **Audience** row into your verifier rather than typing it. The `aud` claim is a JSON array with one element. Accept only this exact value, not any address on your host. |
| Subject prefix | `wimse://identity.anthropic.com/org/<your organization ID>/agent/`. Every token's `sub` claim starts with this prefix and ends with one agent's ID; see the [subject](/docs/claude-tag/admins/federated-access/token-reference#subject) format. Agent IDs aren't shown in the console; your server learns them from the tokens it receives, and they change, for example when a Slack channel is deleted and recreated. |
| Tenant | Your organization ID, the value between `/org/` and `/agent/` in the **Subject prefix**, carried in every token as the `tenant` claim. |
| Expiry | Tokens expire 10 minutes after they're issued. Check `exp`, allowing up to 60 seconds of clock skew. |
## Configure the authorization server
Claude sends a standard JWT bearer grant ([RFC 7523](https://www.rfc-editor.org/rfc/rfc7523)) to the token endpoint as an HTTPS `POST` with `Content-Type: application/x-www-form-urlencoded` and `Accept: application/json`. The form body contains these fields:
```text wrap theme={null}
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<identity token>[&resource=<resource>][&scope=<scopes>]
```
The `resource` ([RFC 8707](https://www.rfc-editor.org/rfc/rfc8707)) and `scope` fields are present only if you set them when connecting the server. No `client_id` or `client_secret` is sent. Register one client for Anthropic's issuer that accepts this grant without client authentication; the subject check is what keeps other organizations out. The request doesn't follow redirects, and the exchange must complete within about 10 seconds.
Your server must:
* Verify the token with a standard JWT or OIDC library configured with the issuer, JWKS URL, audience, and expiry from [Copy the values from the console](#copy-the-values-from-the-console).
* Check the subject. Where your use case allows, accept only the full subjects of your own agents, and update that list when a Slack channel is deleted and recreated. At minimum, reject every token whose `sub` doesn't start with your **Subject prefix**, or equivalently pin `iss` and reject every token whose `tenant` isn't your organization ID. This check is required because every organization's tokens come from the same issuer; see [Authorize on the subject](/docs/claude-tag/admins/federated-access/token-reference#authorize-on-the-subject). The console's connection check doesn't run for token endpoints, so nothing tests this check for you.
* Decide what the agent may do, for example from the agent ID at the end of `sub`, and issue an access token for it. Tokens may carry additional opaque claims; ignore claims you don't recognize.
* Return `200` with a JSON body: `access_token`, `token_type` (`Bearer`, compared without regard to case, and may be omitted), and `expires_in` in seconds.
Each grant carries a fresh token with a new `jti`, so your server may reject a repeated `jti`.
Claude caches the access token when `expires_in` is between 5 minutes and 1 day, inclusive, and reuses it until about 5 minutes before it expires (for tokens shorter than 10 minutes, until half their lifetime has passed). The cache is per channel, so one channel's token is never used for another, and your server may still see more than one grant per channel within a token's lifetime. An `expires_in` outside that range, or none, makes Claude exchange a new token on every request to your APIs.
To refuse a grant, return a standard OAuth 2.0 error response, such as `400` with `{"error": "invalid_grant"}`. Any non-`2xx` status is a refusal. Claude reads only the `error` code and never shows `error_description` to anyone, so log the reason on your side. After a refusal, or any other failed exchange, the agent's request fails with an error, and Claude doesn't try the exchange again for a few seconds; your token endpoint's `Retry-After` header on a `429` or `503` response extends that wait. If one of your APIs answers `401`, or `403` with a `WWW-Authenticate: Bearer` challenge whose error is `invalid_token`, Claude drops the cached token (unless it was just issued) and exchanges a new one on the next request. A plain `403` doesn't trigger this.
## Register the endpoint and connect the server
<Steps>
<Step title="Open the Connect an authorization server dialog">
In **Authorization servers**, click **Connect an authorization server**.
</Step>
<Step title="Enter the token endpoint">
In the **Token endpoint** field, enter the full address starting with `https://`, for example `https://auth.example.com/oauth2/token`. In the **Issuer URL** field, enter your authorization server's issuer identifier, the `iss` value it uses, for example `https://auth.example.com`. That value is the token's audience, and it must be an HTTPS URL on the same host as the token endpoint. Leave the field empty only if your server requires the token endpoint URL as the audience. Then the **Token endpoint** address is the audience. The **Audience** row of the card shows which one will be sent.
</Step>
<Step title="Confirm the subject check and register">
Select the checkbox labeled **This authorization server checks that each token's subject belongs to your organization**. The **Register server** button stays disabled until you do. The checkbox is your confirmation that the server makes the subject check described under [Configure the authorization server](#configure-the-authorization-server), and a server that doesn't must not be connected. Then click **Register server**. The dialog notes that the automatic connection check doesn't run for token endpoints. The endpoint is registered as a gateway with the check marked **Skipped**, and the dialog moves to the second step.
If you close the dialog at that point, the endpoint stays registered and counts toward the limit. To continue later, click **Connect an authorization server** again, enter the same address, and select the checkbox again, which returns you to the second step. Don't use **Add to bundle** on the endpoint's row in the **Gateways** table; that would connect the address as a gateway, after which the server can't be connected.
</Step>
<Step title="Choose the APIs and the Access bundle">
Optionally enter a **Resource**, the API the returned token should be scoped to as an absolute URI (for example `https://api.example.com`), and a **Scope**, space-separated scopes to request. In **Allowed API hosts**, add the hosts Claude may call with the returned token, for example `api.example.com`. A wildcard as the leftmost label matches any subdomain; an entry or wildcard that covers the token endpoint's host is rejected. Then choose a bundle from the **Access bundle** list (or click **New bundle**, enter a **Bundle name**, and click **Create bundle**) and click **Connect server**.
This creates a [connection](/docs/claude-tag/admins/add-connections) in that bundle, labeled **Authorization server** on its **Credentials** tab, with the API hosts under **Allowed hosts**. Agent Proxy attaches the access token as an `Authorization: Bearer` header to every request Claude makes to those hosts. A token endpoint can be connected once in your organization, in one bundle; to use it in several scopes (workspaces or channels), attach that bundle to each.
</Step>
</Steps>
The **Authorization servers** table lists each server by its **Token endpoint**, with its **Access bundle**, its **Allowed hosts**, when it was **Added**, and a **Remove** action. The endpoint also appears in the **Gateways** table with its check marked **Skipped** and a note that a connected authorization server uses it.
## Let agents use the APIs
Claude uses the connection in channels whose scope has the bundle attached. [Attach the bundle to a workspace or channel](/docs/claude-tag/admins/attach-to-scope#attach-the-bundle) if it isn't attached already.
Claude also needs to know what the APIs are for. Add a line like this to the scope's [custom instructions](/docs/claude-tag/admins/attach-to-scope#add-custom-instructions):
```text wrap theme={null}
The internal orders API is at https://api.example.com; see GET /openapi.json for what it offers. Authentication is already set up.
```
The exchange happens in Agent Proxy, outside Claude's sandbox, so neither the identity token nor your access token is visible to Claude, and Claude can't perform the exchange itself.
New threads pick up the connection on their own. In a thread already running, ask Claude to use the API and name its host. If Claude still can't, send [`@Claude !restart`](/docs/claude-tag/users/commands#restart-a-stuck-or-wrong-context-session) at the channel's top level (not inside a thread) to start a fresh session with your organization's current configuration.
## Verify the connection
In a channel whose workspace or channel has the bundle attached, start a new thread and ask Claude to make a small read:
```text wrap theme={null}
@Claude call GET /openapi.json on https://api.example.com and tell me what the API offers.
```
Then check your authorization server's logs for a JWT bearer grant whose token has your **Subject prefix**, and your API's logs for a request carrying the access token it issued. If the grant was refused, your server's own error is the reason; Claude sees only that the request failed. See [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting) for the errors Claude shows.
## Remove the server
In the **Authorization servers** table, click **Remove** in the server's row, then **Remove server** in the confirmation. Claude stops using the connection within about a minute, in existing threads as well as new ones, and the connection is removed from its bundle. An access token your server already issued stays valid with your server until it expires, and Agent Proxy discards it with the connection. The endpoint stays registered as a gateway, so to free its place in the limit, also click **Remove** in its row of the **Gateways** table. To change the address, do both removals, then connect the server again with the new address.
## Common errors
Five messages come up while connecting:
* **"The issuer URL must be an https URL on the same host as the token endpoint. Leave it empty to use the token endpoint as the audience."**: the **Issuer URL** value is not an HTTPS URL on the token endpoint's host. Enter the issuer identifier your server uses there, or clear the field.
* **"This token endpoint is already connected in the bundle"**: the server already has its one connection. [Attach that bundle to the scope](/docs/claude-tag/admins/attach-to-scope#attach-the-bundle) instead.
* **"This organization has reached its limit of 5 registered gateways, which includes token endpoints"**: remove an unused row from the **Gateways** table first.
* **"The allowed hosts can't include the token endpoint's host"**: an **Allowed API hosts** entry, or a wildcard in it, covers the token endpoint's host. Put the token endpoint on a different host from the APIs.
* **"That address is already connected as a gateway. Enter your authorization server's own addresses, or remove the gateway first."**: the token endpoint, or the **Issuer URL** value, is the address of a gateway connected in one of your Access bundles. Enter the server's own addresses, or delete that gateway's connection from its bundle first.
For other dialog messages, see [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting).
## Related resources
* [Give Claude access](/docs/claude-tag/admins/add-connections): the Access bundle and connection model
* [Attach a bundle to a scope](/docs/claude-tag/admins/attach-to-scope): where a connection applies
* [Identity token reference](/docs/claude-tag/admins/federated-access/token-reference): every claim in the token, lifetimes, and key rotation
* [Connect a gateway](/docs/claude-tag/admins/federated-access/connect-a-gateway): the alternative where your own service verifies the token on every request
* [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting): console and runtime errors for every connection type
claude-tag/admins/federated-access/aws New page · 150 lines, new page
# Connect an AWS role ## Before you begin ## Copy the values from the console ## Create the identity provider and role in AWS ## Connect the role in the console ## Let agents use the role ## Verify the connection ## Common errors ## Related resources
A whole new page. There's nothing to diff it against, so here is what it says.
# Connect an AWS role
> Let Claude sign in to an IAM role in your AWS account with a short-lived identity token instead of stored access keys. Covers the identity provider and trust policy to create in AWS, how to connect the role in the console, and how to verify the connection in CloudTrail.
export const BetaNote = () => <Info>Claude Tag is in public beta. Features and behavior described here may change before general availability.</Info>;
<BetaNote />
<Note>AWS roles are connected at [`claude.ai/admin-settings/claude-tag`](https://claude.ai/admin-settings/claude-tag): open **Federated cloud access** in the left navigation and use the **Cloud roles** section. Connecting a role needs an organization Owner, or an admin with full Claude Tag management permission.</Note>
With an AWS role connection, Claude signs in to an IAM role in your AWS account with a short-lived identity token and calls AWS with the role's permissions. No access key is stored in Claude. The token names your organization and the [agent](/docs/claude-tag/concepts/agent-identity) making the request (Claude's identity in one Slack channel), and your role's trust policy decides which tokens to accept. If someone else manages your AWS account, give them the values from the console and the trust policy below; the console steps need a Claude Tag admin.
## Before you begin
* You're an organization Owner, or an admin with full Claude Tag management permission.
* You can create an IAM identity provider and an IAM role in an AWS account in the standard AWS partition. Roles in AWS GovCloud (US) and AWS China can't be connected.
* You know which AWS service hosts Claude will call, for example `s3.us-west-2.amazonaws.com` and `*.s3.us-west-2.amazonaws.com` for S3 in one region.
## Copy the values from the console
In **Cloud roles**, click **Connect an AWS role** and copy the **Issuer**, **Audience**, and **Subject prefix** rows from the **Set the role's trust policy to accept these values** card. Then click **Cancel**; you connect the role after creating it in AWS.
| Value | What it is |
| :------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Issuer | `https://identity.anthropic.com/agents`. The URL of the identity provider you create in AWS, including the `/agents` path. |
| Audience | `sts.amazonaws.com`. The same for every organization, so it can't identify yours. |
| Subject prefix | `wimse://identity.anthropic.com/org/<your organization ID>/agent/`. Every token's subject starts with this prefix and ends with one agent's ID. The trust policy must require at least this prefix. |
## Create the identity provider and role in AWS
<Steps>
<Step title="Create the IAM identity provider">
In the AWS account that owns the role, create an IAM OpenID Connect (OIDC) identity provider with the provider URL `https://identity.anthropic.com/agents` and the audience `sts.amazonaws.com`. Include the `/agents` path. A provider created with the bare hostname, or with any other path, makes every sign-in fail later with an invalid-token or provider error from AWS. You don't need to supply a certificate thumbprint, because AWS verifies the provider's certificate itself.
To confirm the provider, run `aws iam get-open-id-connect-provider --open-id-connect-provider-arn <provider ARN>` and check that `Url` is `identity.anthropic.com/agents` (AWS stores the URL without `https://`) and `ClientIDList` contains `sts.amazonaws.com`.
</Step>
<Step title="Create the role with this trust policy">
Create an IAM role with the trust policy below. Replace the account ID with yours (the rest of the provider ARN is the same for every account), and replace the `sub` value with your **Subject prefix** followed by `*`.
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/identity.anthropic.com/agents"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"identity.anthropic.com/agents:aud": "sts.amazonaws.com"
},
"StringLike": {
"identity.anthropic.com/agents:sub": "wimse://identity.anthropic.com/org/org_01Hx7rQkPzT9sN3mVbJw2eYd/agent/*"
}
}
}
]
}
```
Keep both conditions. Because every organization's tokens come from the same issuer with the same audience, the `sub` condition is the only thing that limits the role to your organization; see [Authorize on the subject](/docs/claude-tag/admins/federated-access/token-reference#authorize-on-the-subject). The wildcard replaces only the agent ID at the end. Never put a wildcard before `/agent/`. `StringEquals` on the prefix never matches, so keep the prefix condition under `StringLike`. Both condition keys start with `identity.anthropic.com/agents:` (the issuer without `https://`).
The prefix condition is the minimum, and it admits every agent in your organization. Where your use case allows, pin the role to specific agents instead, which is the strongest form: use `StringEquals` on `identity.anthropic.com/agents:sub` with one full subject, or a JSON array of full subjects. The console doesn't show agent IDs, so you learn a subject from CloudTrail after a first sign-in under the prefix condition. Agent IDs change when a Slack channel is deleted and recreated, so update the policy when that happens.
</Step>
<Step title="Attach permissions">
Attach a least-privilege permissions policy to the role. For the check under [Verify the connection](#verify-the-connection), the role needs `s3:ListBucket` on the example bucket. Each sign-in gives Claude temporary credentials that last 1 hour, the AWS default. Claude doesn't ask for a different length, and the role's maximum session duration setting doesn't change this. To cut off access before they expire, use the role's **Revoke active sessions** option in IAM or change its permissions.
</Step>
</Steps>
## Connect the role in the console
<Steps>
<Step title="Open the Connect an AWS role dialog">
In **Cloud roles**, click **Connect an AWS role**.
</Step>
<Step title="Enter the role ARN">
In the **Role ARN** field, enter the role's ARN, for example `arn:aws:iam::123456789012:role/ClaudeTag`. The role's name is used as the connection's name.
</Step>
<Step title="Narrow the allowed AWS hosts">
The **Allowed AWS hosts** field starts with `*.amazonaws.com`, which lets Claude use the role with any AWS service. Keep that entry for the first verification, then narrow the list to the hosts Claude needs from the connection's [**Edit connection** dialog](/docs/claude-tag/admins/add-connections#set-allowed-websites) on the bundle's **Credentials** tab. A wildcard covers subdomains only: `*.s3.us-west-2.amazonaws.com` matches `example-reports.s3.us-west-2.amazonaws.com` but not `s3.us-west-2.amazonaws.com`. The AWS CLI and SDKs use both forms for S3, so list both the plain host and the wildcard for each region, and for `us-east-1` also `*.s3.amazonaws.com`, the older global S3 address some tools still use there. Every host must end in `.amazonaws.com`. The sign-in itself goes to the AWS Security Token Service (STS) from Anthropic's side and doesn't need an entry here.
</Step>
<Step title="Confirm the trust policy">
Select the checkbox labeled **The role's trust policy requires the subject prefix shown above**. The **Connect role** button stays disabled until you do. Select it only if the trust policy pins `sub` to one or more full subjects under your **Subject prefix**, or to your prefix followed by `*` under `StringLike`, as described under [Create the identity provider and role in AWS](#create-the-identity-provider-and-role-in-aws).
</Step>
<Step title="Choose an Access bundle and connect">
Choose a bundle from the **Access bundle** list, or click **New bundle**, enter a **Bundle name**, and click **Create bundle**. Then click **Connect role**. This creates a [connection](/docs/claude-tag/admins/add-connections) in that bundle, labeled **AWS role** on its **Credentials** tab, with the hosts you entered under **Allowed hosts**. A role can be connected in one bundle only; to use it in several scopes (workspaces or channels), attach that bundle to each.
</Step>
</Steps>
The **Cloud roles** table has **Role**, **Access bundle**, **Allowed hosts**, **Added**, and **Actions** columns. Each connection's name appears under **Role** with the role's ARN and an **AWS role** chip beneath it, and **Remove** is under **Actions**.
## Let agents use the role
Claude uses the role in channels whose scope has the bundle attached. [Attach the bundle to a workspace or channel](/docs/claude-tag/admins/attach-to-scope#attach-the-bundle) if it isn't attached already.
Claude also needs to know what the role is for. Add a line like this to the scope's [custom instructions](/docs/claude-tag/admins/attach-to-scope#add-custom-instructions):
```text wrap theme={null}
Use the AWS CLI to read the S3 bucket example-reports in us-west-2. AWS access is already set up.
```
Claude calls AWS with `curl`, an AWS SDK, or the AWS CLI, as with an [AWS SigV4 credential](/docs/claude-tag/admins/connections/custom#aws-sigv4). [Agent Proxy](/docs/claude-tag/concepts/agent-identity#agent-proxy) signs each request at the network boundary with the role's temporary credentials, so the sandbox never holds them.
New threads pick up the connection on their own. In a thread already running, ask Claude to use AWS. If Claude still can't, send [`@Claude !restart`](/docs/claude-tag/users/commands#restart-a-stuck-or-wrong-context-session) at the channel's top level (not inside a thread) to start a fresh session with your organization's current configuration.
## Verify the connection
In a channel whose workspace or channel has the bundle attached, start a new thread and ask Claude to make a small read (replace `example-reports` with a bucket the role can read):
```text wrap theme={null}
@Claude list the objects in the S3 bucket example-reports and tell me how many there are.
```
Then check CloudTrail in the AWS account for an `AssumeRoleWithWebIdentity` event on your role whose identity provider names `identity.anthropic.com/agents`. Claude signs in at the global STS endpoint, `sts.amazonaws.com`, so the event is recorded in the US East (N. Virginia) region; look there or in a multi-region trail, and allow a few minutes for it to appear. The role session name is an opaque ID for the Claude session that signed in. Claude may reuse one sign-in's credentials for most of the hour across threads in the same channel, so not every request produces a sign-in event. After AWS denies a request, Claude signs in again on the next one.
If Claude reports that the request was refused, CloudTrail usually shows why.
* No sign-in event at all means the request never reached AWS, most often because the host isn't in the connection's **Allowed AWS hosts**.
* An invalid-token or provider error on the sign-in usually means the identity provider's URL doesn't exactly match the issuer, `https://identity.anthropic.com/agents`.
* `AccessDenied` on the sign-in means the trust policy didn't accept the token. Check the `sub` condition and the condition-key prefix.
* A denied action after a successful sign-in means AWS denied the action. Check the role's permissions policy first, then any bucket policy, permissions boundary, or service control policy.
See [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting) for the errors Claude shows.
To disconnect a role, click **Remove** in the role's row of the **Cloud roles** table, then **Remove role** in the confirmation. Claude stops using the role within about a minute, in existing threads as well as new ones, and the connection is removed from its bundle. Credentials from an earlier sign-in stay valid in AWS until they expire, within 1 hour; they're held only by Agent Proxy, never by Claude's sandbox.
## Common errors
Two messages come up while connecting:
* **"This role is already connected in the bundle"**: the role already has its one connection. [Attach that bundle to the scope](/docs/claude-tag/admins/attach-to-scope#attach-the-bundle) instead.
* **"Enter a role ARN like `arn:aws:iam::123456789012:role/ClaudeTag`"**: the **Role ARN** field rejected the value, most often because the ARN is in the AWS GovCloud (US) or AWS China partition, which can't be connected.
For other dialog messages, see [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting).
## Related resources
* [Give Claude access](/docs/claude-tag/admins/add-connections): the Access bundle and connection model
* [Attach a bundle to a scope](/docs/claude-tag/admins/attach-to-scope): where a role connection applies
* [Identity token reference](/docs/claude-tag/admins/federated-access/token-reference): every claim in the token, lifetimes, and key rotation
* [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting): console and runtime errors for every connection type
* [AWS SigV4 credential](/docs/claude-tag/admins/connections/custom#aws-sigv4): the stored-key alternative, and how Claude signs AWS requests
claude-tag/admins/federated-access/connect-a-gateway New page · 120 lines, new page
# Connect a gateway ## Before you begin ## Copy the values and deploy the gateway ## Register the gateway in the console ## Let agents reach the gateway ## Verify the connection ## Common errors ## Related resources
A whole new page. There's nothing to diff it against, so here is what it says.
# Connect a gateway
> Connect a gateway you run so Claude Tag can call your internal services with a short-lived identity token instead of a stored credential. Covers what the gateway must check, how to register it in the console, and how to verify the connection.
export const BetaNote = () => <Info>Claude Tag is in public beta. Features and behavior described here may change before general availability.</Info>;
<BetaNote />
<Note>Gateways are connected at [`claude.ai/admin-settings/claude-tag`](https://claude.ai/admin-settings/claude-tag): open **Federated cloud access** in the left navigation and use the **Gateways** section. Connecting a gateway needs an organization Owner, or an admin with full Claude Tag management permission.</Note>
A gateway is a service you run between Claude and your internal systems. Every request Claude sends it carries a signed identity token naming your organization and the [agent](/docs/claude-tag/concepts/agent-identity) making the request (Claude's identity in one Slack channel). The gateway checks the token, decides what that agent may do, and forwards the request with your own credentials. No long-lived credential for your systems is stored in Claude.
Two terms recur on this page. The **subject check** is what your gateway does to every token, confirming it belongs to your organization. The **connection check** is what the console does once, when you connect the gateway, confirming that your gateway performs the subject check.
## Before you begin
* You're an organization Owner, or an admin with full Claude Tag management permission.
* The gateway has a public HTTPS address with a domain name, such as `https://gateway.example.com`, on the standard HTTPS port. The console rejects a path, port, trailing slash, IP address, private-network name, Anthropic-owned host, or cloud token-exchange host.
* The gateway can reach `https://identity.anthropic.com` to fetch Anthropic's signing keys.
* If you start from Anthropic's [sample gateway](https://github.com/anthropics/claude-tag-wif-gateway-sample) (Python, Apache 2.0), terminate TLS in front of it, because it listens on plain HTTP, and set its `audience` to the public address you register.
* An organization can register up to 5 addresses, counting gateways and authorization-server token endpoints together.
## Copy the values and deploy the gateway
In **Gateways**, click **Connect a gateway** and copy the **Issuer**, **JWKS URL**, **Subject prefix**, and **Control subject** rows from the **Set your gateway to accept these values** card, which appears as soon as the dialog opens and doesn't depend on the address. Then click **Cancel**; you register the gateway after deploying it.
Claude authenticates with a JSON Web Token (JWT) in the `Authorization: Bearer` header of every request. It reuses one token for a session's requests for about five minutes, or until your gateway answers 401, and then requests a new one, so don't treat a repeated `jti` as a replay. Verify it with a standard JWT or OpenID Connect (OIDC) library configured with these values.
| Value | What to configure |
| :-------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Issuer | `https://identity.anthropic.com/agents`, matched exactly. The OIDC discovery document is at `https://identity.anthropic.com/agents/.well-known/openid-configuration`. |
| Signing keys | The JSON Web Key Set (JWKS) named by `jwks_uri` in the discovery document, `https://identity.anthropic.com/agents/jwks.json`. Accept ES256 only. On an unknown key ID, refetch the key set before rejecting the token. |
| Audience | Your gateway address as the console stores it (the console converts the host to lowercase), for example `https://gateway.example.com`. The `aud` claim is a JSON array with one element, so use the library's audience option. |
| Subject prefix | `wimse://identity.anthropic.com/org/<your organization ID>/agent/`, copied from the dialog. Every token's `sub` claim names one agent in one organization. |
| Tenant | Your organization ID, the value between `/org/` and `/agent/` in the **Subject prefix**, carried in every token as the `tenant` claim. |
| Control subject | A reserved test identity in your organization, copied from the dialog. Anthropic uses it only for the connection check. |
| Expiry | Tokens expire 10 minutes after they're issued. Check `exp`, allowing up to 60 seconds of clock skew. |
The subject check is yours to implement, and it's required, because every organization's tokens come from the same issuer; see [Authorize on the subject](/docs/claude-tag/admins/federated-access/token-reference#authorize-on-the-subject). Implement the check in one of two forms, strongest first:
* Accept only an explicit list of your own agents' full subjects, when your use case allows it. The sample gateway does this by default and offers the prefix form below as an opt-in setting. Agent IDs change when a Slack channel is deleted and recreated, so you update the list when that happens.
* Otherwise, reject every token whose `sub` doesn't start with your **Subject prefix**, or pin `iss` and `tenant` together. The `tenant` claim is your organization ID, the same value the subject carries between `/org/` and `/agent/`, so checking it is the subject check in claim form. This is the minimum.
For the connection check, the gateway also needs a route at the address itself, with no path, that answers an empty `POST` by verifying the token and reporting whether the subject is accepted (2xx if it is, 401 or 403 if not) and does nothing else. Agents normally call a path; the root route exists for the connection check, and an agent that calls it gets the same accept-or-reject answer. The sample gateway calls this its readiness route. The check sends it two requests, and any other status from either one fails the check:
* A token valid in every other way (your audience, Anthropic's issuer and signature, unexpired) whose subject isn't your organization. The gateway must answer 401 or 403. Only the `tenant` or subject check can reject it.
* A token for the **Control subject**. The gateway must answer 2xx. A gateway that lists exact subjects must include the control subject in its list, and a prefix or `tenant` check accepts it on its own, because it belongs to your organization. Either way, map it to no service.
With the sample gateway, set `audience` in `config.yaml` to your registered address and add a `principals` entry for the **Control subject** with `allowed_services: []` (the example config ships with a placeholder organization ID). By default the sample accepts only the subjects listed under `principals`; an agent that isn't listed gets 403, and the sample logs its full subject so you can add it. To accept every agent in your organization instead, add an `organization_principals` entry keyed by your **Subject prefix**. The control subject still needs its exact `principals` entry either way.
Never forward the Claude Tag token downstream; replace the `Authorization` header with your own credential.
## Register the gateway in the console
<Steps>
<Step title="Open the Connect a gateway dialog">
In **Gateways**, click **Connect a gateway**.
</Step>
<Step title="Enter the gateway address">
In the **Gateway address** field, enter the host only, in lowercase, starting with `https://`, for example `https://gateway.example.com`. This address is the token's audience.
</Step>
<Step title="Confirm the subject check">
Select the **This gateway checks that each token's subject belongs to your organization** checkbox. The **Run check and connect** button stays disabled until you do. Select it only if the gateway rejects every subject outside your organization, by explicit list, by prefix, or by the `tenant` claim.
</Step>
<Step title="Run the connection check">
Leave the **Run the check** option selected and click **Run check and connect**. The check can take up to a minute. If it fails, nothing is registered; see [Common errors](#common-errors). If the gateway can't be reached from the internet yet, select the **Skip the check** option, enter a **Reason for skipping**, and click **Connect without the check**. The reason is shown in the **Gateways** table. Entering an address that is already registered runs the check again (unless you skip it) without changing the stored result, then moves to the bundle step.
</Step>
<Step title="Add the gateway to an Access bundle">
Choose a bundle from the **Access bundle** list, or click **New bundle**, enter a **Bundle name**, and click **Create bundle**. Then click **Add to bundle**. This creates a connection in that bundle, labeled **Gateway** on its **Credentials** tab, with the gateway's host as its allowed website. A gateway can be in one bundle only; to use it in several scopes, attach that bundle to each. Click **Not now** to finish without a bundle.
</Step>
</Steps>
The **Gateways** table lists each gateway with its **Connection check** result (**Passed**, or **Skipped** with your reason), when it was added, and **Add to bundle** and **Remove** actions. For a gateway that is already registered, skip the dialog's first step: click **Add to bundle** in the gateway's row of the **Gateways** table, which opens the dialog at the bundle step. Entering the address again in **Connect a gateway** also reaches the bundle step, but unless you skip the check it runs again first, and that run counts toward the check limit.
## Let agents reach the gateway
Claude uses the gateway in channels whose scope has the bundle attached. [Attach the bundle to a workspace or channel](/docs/claude-tag/admins/attach-to-scope#attach-the-bundle) if it isn't attached already.
Claude also needs to know the gateway exists. Add a line like this to the scope's [custom instructions](/docs/claude-tag/admins/attach-to-scope#add-custom-instructions):
```text wrap theme={null}
Internal APIs are behind https://gateway.example.com. Call GET /list-services there to see what is available.
```
The sample gateway serves `GET /list-services` for this; an OpenAPI document named in the instructions works as well.
New threads pick up the connection on their own. In a thread already running, ask Claude to use the gateway and include its address. If Claude still can't see the gateway, send [`@Claude !restart`](/docs/claude-tag/users/commands#restart-a-stuck-or-wrong-context-session) at the channel's top level to start a fresh session with your organization's current configuration.
## Verify the connection
In a channel under the bundle's scope, start a new thread and ask Claude to make a small read through the gateway:
```text wrap theme={null}
@Claude call GET /list-services on https://gateway.example.com and tell me what it returns.
```
If your gateway logs subjects and decisions, confirm the request arrived with a token that passed every check and a subject starting with your **Subject prefix**. [Agent Proxy](/docs/claude-tag/concepts/agent-identity#agent-proxy) attaches the token at the network boundary; the model and the sandbox are not given it.
To disconnect a gateway, click **Remove** in the gateway's row of the **Gateways** table. Claude stops using the gateway at once. A token issued before the removal stays valid until it expires, within 10 minutes.
## Common errors
Two messages come up while connecting:
* **"The check didn't pass"**: the gateway isn't reachable from the internet over HTTPS, its root route doesn't answer an empty `POST` directly, or the subject check is missing or rejects the **Control subject**. See [The check didn't pass](/docs/claude-tag/admins/federated-access/troubleshooting#the-check-didn%E2%80%99t-pass).
* **A bundle-step message that the gateway is already in a bundle**: a gateway can be in one bundle only. [Attach that bundle to the scope](/docs/claude-tag/admins/attach-to-scope#attach-the-bundle) instead.
For other dialog messages, see [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting).
## Related resources
* [Give Claude access](/docs/claude-tag/admins/add-connections): the Access bundle and connection model
* [Attach a bundle to a scope](/docs/claude-tag/admins/attach-to-scope): where a gateway connection applies
* [Identity token reference](/docs/claude-tag/admins/federated-access/token-reference): every claim in the token, lifetimes, and key rotation
* [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting): console and runtime errors for every connection type
* [Sample gateway](https://github.com/anthropics/claude-tag-wif-gateway-sample): a reference gateway with offline tests
claude-tag/admins/federated-access/gcp New page · 159 lines, new page
# Connect a Google Cloud identity ## Before you begin ## Copy the values from the console ## Create the pool and provider in Google Cloud ## Grant access ### Without a service account ### With a service account ## Connect the identity in the console ## Let agents use the identity ## Verify the connection ## Common errors ## Related resources
A whole new page. There's nothing to diff it against, so here is what it says.
# Connect a Google Cloud identity
> Let Claude call Google Cloud through workload identity federation with a short-lived identity token instead of a service account key. Covers the pool, provider, and IAM grants to create, with or without a service account, and how to connect the identity in the console.
export const BetaNote = () => <Info>Claude Tag is in public beta. Features and behavior described here may change before general availability.</Info>;
<BetaNote />
<Note>Google Cloud identities are connected at [`claude.ai/admin-settings/claude-tag`](https://claude.ai/admin-settings/claude-tag): open **Federated cloud access** in the left navigation and use the **Cloud roles** section. Connecting an identity needs an organization Owner, or an admin with full Claude Tag management permission.</Note>
With a Google Cloud identity connection, Claude exchanges a short-lived identity token at a workload identity pool you create and calls Google Cloud APIs with the result. No service account key is stored in Claude. The token names your organization and the [agent](/docs/claude-tag/concepts/agent-identity) making the request (Claude's identity in one Slack channel), and your pool's attribute condition decides which tokens to accept. If someone else manages your Google Cloud project, give them the values from Claude's admin settings and the settings below; the console steps need a Claude Tag admin.
Before you start, decide whether Claude acts as the federated identity itself, with roles granted to it directly, or as a service account you create. Both forms are covered below.
## Before you begin
* You're an organization Owner, or an admin with full Claude Tag management permission.
* You can create a workload identity pool and provider in a Google Cloud project (any project; it doesn't have to own the resources) and grant IAM roles on the resources Claude will use. Use a workload identity pool; workforce identity pools aren't supported.
* If an organization policy restricts which issuers your workload identity pools may trust, allow `https://identity.anthropic.com/agents` first.
* You know which Google API hosts Claude will call, for example `storage.googleapis.com`.
## Copy the values from the console
In **Cloud roles**, click **Connect a Google Cloud identity** and copy the **Issuer** and **Subject prefix** rows from the **Set the workload identity provider to accept these values** card (the **JWKS URL** row isn't needed, because Google reads the keys from the issuer). Then click **Cancel**; you connect the identity after setting up Google Cloud.
| Value | What it is |
| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Issuer | `https://identity.anthropic.com/agents`. The issuer URL of the provider you create in the pool. |
| Subject prefix | `wimse://identity.anthropic.com/org/<your organization ID>/agent/`. Every token's subject starts with this prefix and ends with one agent's ID. The organization ID between `/org/` and `/agent/` is also the value of the token's `tenant` claim. |
## Create the pool and provider in Google Cloud
Create a workload identity pool and an OpenID Connect (OIDC) provider in it with these settings. Replace `<your organization ID>` with the ID from your **Subject prefix**.
| Setting | Value |
| :------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Issuer URL | `https://identity.anthropic.com/agents` |
| Allowed audiences | Leave at Google's default, the provider's own resource name, which Google accepts with or without a leading `https:`. Claude sends the name exactly as you enter it in Claude's admin settings, so if you pin allowed audiences instead, pin that same spelling. |
| Attribute mapping | `google.subject` = `assertion.sub`. You can also map `attribute.org` = `assertion.tenant`, which lets you grant roles to all of your organization's agents as one principal set in [Grant access](#grant-access). |
| Attribute condition | `assertion.sub == "<full subject>"` for one agent. To allow several agents, join one comparison per agent with CEL's or operator. To admit every agent in your organization instead, `assertion.sub.startsWith("wimse://identity.anthropic.com/org/<your organization ID>/agent/")`. |
Google doesn't require an attribute condition, and nothing checks it for you. Without one, agents of every other Claude Tag organization can authenticate to your pool, because every organization's tokens come from the same issuer; see [Authorize on the subject](/docs/claude-tag/admins/federated-access/token-reference#authorize-on-the-subject). The condition on `assertion.sub` is the subject check every connection type needs. The exact form accepts only the agents you list, and the prefix form accepts every agent in your organization, because every subject carries your organization ID between `/org/` and `/agent/`.
Listing exact subjects is the strongest form. The prefix form is the minimum, and it admits every agent in your organization to the pool. With the prefix form, you can still grant IAM roles only to individual agents' `principal://` members, as shown under [Grant access](#grant-access). Claude's admin settings don't show agent IDs, so you learn a subject from Cloud Audit Logs after a first exchange, and you update the condition or the grants when a Slack channel is deleted and recreated, because the new channel's agent has a new ID.
Mapping `attribute.org` from `assertion.tenant` is optional. The `tenant` claim carries the same organization ID as the subject, so the condition `attribute.org == "<your organization ID>"` is the prefix check in claim form. The mapping is standard Google attribute mapping.
## Grant access
Choose one of the two forms. The console step "Name the service account, or leave the field empty" depends on your choice.
### Without a service account
Grant IAM roles on each resource directly to the federated identity. To grant a role to one channel's agent, use the agent's full subject, unescaped, for example `principal://iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/claude/subject/wimse://identity.anthropic.com/org/<your organization ID>/agent/<agent ID>`.
To grant a role to all of your organization's agents at once, map `attribute.org` from `assertion.tenant` as described under [Create the pool and provider in Google Cloud](#create-the-pool-and-provider-in-google-cloud), and use the principal set
```text wrap theme={null}
principalSet://iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/claude/attribute.org/<your organization ID>
```
with your project number, pool ID, and organization ID.
Grant only what Claude needs, and grant nothing to the pool-wide principal set (`principalSet://…/workloadIdentityPools/claude/*`). In this form, don't grant the federated identity any permission that mints credentials, such as `iam.serviceAccounts.getAccessToken`, `iam.serviceAccounts.signJwt`, or service account key creation, because Claude could then obtain a Google credential that works outside Claude. (The form with a service account grants one such permission on purpose, on one service account.)
### With a service account
Create a dedicated service account in any project and grant it the roles Claude needs. The console accepts only addresses of the form `<name>@<project>.iam.gserviceaccount.com`, so the default Compute Engine and App Engine service accounts can't be used. Enable the IAM Service Account Credentials API in the service account's project. Then grant the **Workload Identity User** role (`roles/iam.workloadIdentityUser`) to the same `principalSet://` or `principal://` member as in [Without a service account](#without-a-service-account), on the service account's own IAM policy rather than on the project. Don't grant the service account any permission to mint further credentials or create keys.
## Connect the identity in the console
<Steps>
<Step title="Open the Connect a Google Cloud identity dialog">
In **Cloud roles**, click **Connect a Google Cloud identity**.
</Step>
<Step title="Enter the provider resource name">
In the **Workload identity provider** field, enter `//iam.googleapis.com/` followed by the provider's full name as Google reports it, for example `//iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/claude/providers/agents`. Use the project number, not the project ID (find it on the project's dashboard in the Google Cloud console). The value is stored as you type it and is the token's audience.
</Step>
<Step title="Name the service account, or leave the field empty">
In the **Service account to act as (optional)** field, enter the service account's email, for example `[email protected]`, if you chose the form with a service account. Leave the field empty to have Claude act as the federated identity itself. The connection is named after the service account, or after the provider's ID (the last part of its resource name) when there is none.
</Step>
<Step title="Decide whether to block credential minting">
The **Block requests that mint new credentials** checkbox is selected by default. With it selected:
* Claude can't use this identity to call Google endpoints that create keys, tokens, or other credentials, even if IAM would allow the call.
* Requests to a list of services that deal in credentials are refused entirely. See [what the credential-minting block refuses](/docs/claude-tag/admins/federated-access/limits#what-the-credential-minting-block-refuses) on the limits page.
* gRPC calls are refused, so tell Claude in the custom instructions to use the REST transport of client libraries such as Spanner, Bigtable, Firestore, and Pub/Sub.
If Claude needs one of the refused services, clear the checkbox and rely on your IAM grants alone. The token exchange itself, including acting as the service account, happens inside Agent Proxy and isn't affected by this checkbox or by the allowed hosts.
</Step>
<Step title="Narrow the allowed Google hosts">
Replace the prefilled `*.googleapis.com` entry in the **Allowed Google hosts** field with the hosts Claude needs, for example `storage.googleapis.com`. A wildcard as the leftmost label, such as `*.storage.googleapis.com`, matches any subdomain but not the name itself. Every host must be `googleapis.com`, a subdomain of it, or a subdomain of `clients6.google.com`. You can change the list later from the connection's [**Edit connection** dialog](/docs/claude-tag/admins/add-connections#set-allowed-websites) on the bundle's **Credentials** tab.
</Step>
<Step title="Confirm the attribute condition">
Select the checkbox labeled **The provider's attribute condition requires the subject prefix shown above**. The **Connect identity** button stays disabled until you do. Select the checkbox only if the provider's attribute condition pins `assertion.sub` to one or more full subjects under your **Subject prefix**, or at minimum pins `assertion.sub` to your **Subject prefix** (or, if you mapped it, `attribute.org` to your organization ID), as described under [Create the pool and provider in Google Cloud](#create-the-pool-and-provider-in-google-cloud).
</Step>
<Step title="Choose an Access bundle and connect">
Choose a bundle from the **Access bundle** list, or click **New bundle**, enter a **Bundle name**, and click **Create bundle**. Then click **Connect identity**. This creates a [connection](/docs/claude-tag/admins/add-connections) in that bundle, labeled **Google Cloud identity** on its **Credentials** tab, with the hosts you entered under **Allowed hosts**. The same provider can be connected more than once, for example once with a service account and once without, as long as no two Google Cloud connections in one bundle share a host under **Allowed hosts**. To use a connection in several scopes (workspaces or channels), attach its bundle to each.
</Step>
</Steps>
The **Cloud roles** table has **Role**, **Access bundle**, **Allowed hosts**, **Added**, and **Actions** columns. Each connection's name appears under **Role** with the provider and a **Google Cloud** chip beneath it, which also names the service account when the connection acts as one, and **Remove** is under **Actions**.
## Let agents use the identity
Claude uses the identity in channels whose scope has the bundle attached. [Attach the bundle to a workspace or channel](/docs/claude-tag/admins/attach-to-scope#attach-the-bundle) if it isn't attached already.
Claude also needs to know what the identity is for. Add a line like this to the scope's [custom instructions](/docs/claude-tag/admins/attach-to-scope#add-custom-instructions):
```text wrap theme={null}
Use the Cloud Storage JSON API at storage.googleapis.com to read the bucket example-reports. Google Cloud access is already set up.
```
[Agent Proxy](/docs/claude-tag/concepts/agent-identity#agent-proxy) exchanges the token and attaches the resulting Google credential to each request at the network boundary, so the sandbox never holds it.
New threads pick up the connection on their own. In a thread already running, ask Claude to use Google Cloud. If Claude still can't, send [`@Claude !restart`](/docs/claude-tag/users/commands#restart-a-stuck-or-wrong-context-session) at the channel's top level (not inside a thread) to start a fresh session with your organization's current configuration.
## Verify the connection
In a channel whose workspace or channel has the bundle attached, start a new thread and ask Claude to make a small read (replace `example-reports` with a bucket the identity can read):
```text wrap theme={null}
@Claude list the objects in the Cloud Storage bucket example-reports and tell me how many there are.
```
Claude's reply tells you whether the read worked. For log evidence, enable Data Access audit logs beforehand for the Security Token Service API, for Cloud Storage, and, with a service account, for the IAM Service Account Credentials API, because Google keeps them off by default. The Security Token Service entry records each token exchange, with Google's reason when it refuses one, which Claude's own error doesn't show. The Cloud Storage entry shows the caller as the service account, or as the federated identity with the agent's full subject.
If Claude reports that the request was refused, the two most common causes are these:
* A token refused by your provider usually means the attribute condition didn't accept it. Check the organization ID in the condition, then the issuer URL and the allowed audience.
* A permission error on the API call means the role grant is missing or too narrow.
See [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting) for the errors Claude shows and the other causes.
To disconnect an identity, click **Remove** in the identity's row of the **Cloud roles** table, then **Remove role** in the confirmation. Claude stops using the identity within about a minute, in existing threads as well as new ones, and the connection is removed from its bundle. A Google credential from an earlier exchange stays valid with Google until it expires, held only by Agent Proxy, never by Claude's sandbox. To end the trust on the Google side as well, delete the provider or remove the IAM bindings.
## Common errors
Two messages come up while connecting:
* **A message that a connection "already covers" a host "in this bundle"**: another Google Cloud connection in the bundle you chose already has that host under **Allowed hosts**, so Claude would never use the new connection for it. Remove the shared host or choose another bundle.
* **A rejected Workload identity provider or Service account to act as value**: the value doesn't match the form the field describes, usually because the resource name carries the project ID instead of the project number, or the service account is a default one.
For other dialog messages, see [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting).
## Related resources
* [Give Claude access](/docs/claude-tag/admins/add-connections): the Access bundle and connection model
* [Attach a bundle to a scope](/docs/claude-tag/admins/attach-to-scope): where an identity connection applies
* [Identity token reference](/docs/claude-tag/admins/federated-access/token-reference): every claim in the token, lifetimes, and key rotation
* [Limits](/docs/claude-tag/admins/federated-access/limits): what the credential-minting block refuses, and the other limits for Google Cloud identities
* [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting): console and runtime errors for every connection type
* [BigQuery](/docs/claude-tag/admins/connections/bigquery): the stored-key alternative for one Google service
claude-tag/admins/federated-access/limits New page · 97 lines, new page
# Limits for federated cloud access ## Where federated connections work ## Identity token ## Gateways ## AWS roles ## Google Cloud identities ### What the credential-minting block refuses ## Authorization servers ## Testing ## Related resources
A whole new page. There's nothing to diff it against, so here is what it says.
# Limits for federated cloud access > Counts, lengths, lifetimes, and unsupported configurations for Claude Tag's federated cloud access: gateways, AWS roles, Google Cloud identities, and authorization servers. export const BetaNote = () => <Info>Claude Tag is in public beta. Features and behavior described here may change before general availability.</Info>; <BetaNote /> This page collects the fixed limits of Federated cloud access in one place. ## Where federated connections work Federated connections are available to Claude in Slack channels, where it acts under your organization's [agent identity](/docs/claude-tag/concepts/agent-identity). They aren't available in direct messages, which run on the individual's own claude.ai account, and they need an Anthropic-hosted environment; Claude can't use them in a [self-hosted environment](/docs/claude-tag/concepts/security-and-data). ## Identity token | Limit | Value | | :---------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Token lifetime | 10 minutes. Tokens can't be revoked before they expire. When you remove a gateway, Claude stops using it at once; when you remove a cloud role or authorization server, within about a minute (current behavior, may change). A token issued before the removal stays valid until it expires. | | Signing algorithm | ES256 only. | | Claims | See the [identity token reference](/docs/claude-tag/admins/federated-access/token-reference#claims); verifiers must ignore claims they don't recognize. | ## Gateways | Limit | Value | | :------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Registered addresses per organization | 5, counting gateways and authorization-server token endpoints together. | | Token reuse | Claude reuses one token for a session's requests to the same gateway for about five minutes, half the token's lifetime, or until the gateway answers 401, and then requests a new one (current behavior, may change). A gateway sees the same `jti` on many requests. | | Gateway address | An HTTPS host name only, with no path, port, query, or trailing slash. The host name needs a domain, like `gateway.example.com`, uses only letters, numbers, hyphens, and dots, and has at most 253 characters (current behavior, may change). The console rejects an IP address, a private-network name, an Anthropic-owned host, or a host cloud providers use for token exchange, and names the reason. The connection check also refuses a host name that resolves to a private address. | | One connection per gateway | A gateway connected in one Access bundle can't be connected again in another. Attach that bundle to each scope that needs the gateway. | | [Allowed websites](/docs/claude-tag/admins/add-connections#set-allowed-websites) on the gateway's connection | Exactly the gateway's host, the only host Claude sends the token to. It can't be widened or given a wildcard. | | Connection check | Runs only against an HTTPS host with no path. The console sends two `POST` requests to the address, each with an empty body and a test token, doesn't follow redirects, and can take up to a minute. [Connect a gateway](/docs/claude-tag/admins/federated-access/connect-a-gateway) lists the expected responses. The console refuses a check that runs many times in quick succession and says how long to wait. | | Same address twice in one organization | Entering an address that is already registered runs the connection check again (unless you skip it) without changing the stored result, then moves to the bundle step. The run counts toward the check limit. | ## AWS roles | Limit | Value | | :---------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Role ARN** | A commercial-partition IAM role, `arn:aws:iam::<account>:role/<name>`. AWS GovCloud and AWS China roles aren't supported. | | **Allowed AWS hosts** | Hosts ending in `.amazonaws.com` only, for example `s3.us-east-1.amazonaws.com` or `*.amazonaws.com`. | | Role session | 1 hour. The exchange doesn't ask for a longer session, so raising the role's maximum session duration has no effect. Claude reuses one session's credentials for the same agent until shortly before they expire, or until AWS answers a request with 403 (current behavior, may change). | | Token audience | `sts.amazonaws.com`, the same for every organization. Condition the trust policy on the `sub` claim as well as the audience; see [Authorize on the subject](/docs/claude-tag/admins/federated-access/token-reference#authorize-on-the-subject). | | One connection per role | A role can be connected once in your organization. | ## Google Cloud identities | Limit | Value | | :------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Workload identity provider** | The full resource name of a provider in a workload identity pool under a numeric project, `//iam.googleapis.com/projects/<number>/locations/global/workloadIdentityPools/<pool>/providers/<provider>`. Workforce identity pools aren't supported. | | **Service account to act as** | Optional. A service account, `<name>@<project>.iam.gserviceaccount.com`. Default compute and App Engine service accounts aren't accepted. Leave it empty to call Google Cloud as the federated identity itself. | | **Allowed Google hosts** | `googleapis.com`, a subdomain of it, or a subdomain of `clients6.google.com`. | | OAuth scope | `https://www.googleapis.com/auth/cloud-platform`, always. Effective permissions come from IAM. | | **Block requests that mint new credentials** | On by default. When on, requests to Google's credential-minting and credential-delivering endpoints are refused, including over gRPC; see [What the credential-minting block refuses](#what-the-credential-minting-block-refuses). The block is best effort and doesn't replace least-privilege IAM. | | Google Cloud connections in one bundle | No two Google Cloud connections in the same Access bundle can cover the same host under **Allowed hosts**, whatever their providers or service accounts. A wildcard such as `*.googleapis.com` covers every subdomain but not `googleapis.com` itself. The same provider can be connected again with different hosts, or in another bundle. | ### What the credential-minting block refuses With **Block requests that mint new credentials** on, Agent Proxy refuses these requests before they reach Google, whatever IAM would allow (current behavior, may change): * Every request to these services, whether the service is named in the host or in the path: Security Token Service, IAM, IAM Service Account Credentials, API Keys, Firebase Authentication (Identity Toolkit and Secure Token), Cloud Workstations, Cloud SQL Admin, AlloyDB, Connect Gateway, GKE Hub, Certificate Authority Service, Identity-Aware Proxy, Apigee, Secret Manager, Parameter Manager, OS Login, Cloud Shell, Cloud Identity, the Google Workspace Admin SDK, Cloud KMS, Cloud Tasks, Cloud Scheduler, Eventarc, Workflows and Workflow Executions, API Gateway, Application Integration, Deployment Manager, Cloud Build, Cloud Composer, Dataform, AI Platform Training and Prediction, Google Kubernetes Engine, Dataproc, OS Config, Dialogflow, Storage Transfer Service, BigQuery Data Transfer Service, and Vertex AI Workbench. * On every other Google service, methods whose response carries a credential or signature, matched by method name. For example `generate`, `refresh`, or `exchange` methods ending in `Token`, `Cert`, `Certificate`, `Credential`, `Credentials`, `Url`, `Secret`, `Password`, or `Key`, and `exchangeAppAttestAssertion` and `exchangeAppAttestAttestation` (Bigtable's `generateConsistencyToken`, which returns no credential, passes). * Signing methods: `sign`, `signJwt`, `signBlob`, `signSshPublicKey`, and their `asymmetric`, `mac`, and `raw` forms. * `show`, `reset`, or `retrieve` methods ending in `Credential`, `Credentials`, `Password`, `Secret`, or `SecretKey`, plus `add` or `import` methods ending in `PublicKey`, and methods starting with `signUp` or `signIn`. * `setIamPolicy` on any resource, and Compute Engine `setMetadata`, `setCommonInstanceMetadata`, `updatePerInstanceConfigs`, `patchPerInstanceConfigs`, instance updates, and instance settings writes. * Cloud Storage IAM and ACL writes, and HMAC key creation. * IAM service account key creation and upload; API Keys `keyString` and Memorystore `authString` reads. * Pub/Sub subscription creation, update, and `modifyPushConfig`, and Cloud Monitoring uptime check creation and changes. * Google's OAuth 2.0 token endpoint (`oauth2.googleapis.com/token`), HTTP batch requests (a path that starts with `/batch`), and any request framed as gRPC, gRPC-Web, or `$rpc`. On services not listed above, reads such as `getIamPolicy`, `testIamPermissions`, and `tokeninfo` pass. If Claude needs one of the refused services, clear the checkbox on that connection and rely on IAM alone. ## Authorization servers | Limit | Value | | :-------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Token endpoint** | A full HTTPS URL of at most 256 characters (current behavior, may change), with an optional path and no port, query, fragment, user name, password, spaces, or special characters. The same host rules as a gateway address apply, and a trailing slash is dropped. | | Token audience | Your authorization server's issuer identifier as you entered it (an HTTPS URL on the same host as the token endpoint, with the same address rules), or the token endpoint URL exactly when you left the issuer identifier empty. It can't be changed after the server is connected. | | **Resource** | Optional. An absolute URI with no fragment, at most 256 characters with no spaces (current behavior, may change). | | **Scope** | Optional. Space-separated scope words with no quotes or backslashes, at most 256 characters in total (current behavior, may change). | | **Allowed API hosts** | Must not include the token endpoint's host. | | Token exchange | A form-encoded `POST` that doesn't follow redirects and must complete within about 10 seconds (current behavior, may change). | | Access token reuse | Reused until about five minutes before it expires (for tokens shorter than 10 minutes, until half their lifetime has passed) when `expires_in` is between 5 minutes and 1 day. When `expires_in` is missing or shorter, the token is used for one request. When it is longer than a day, the token isn't cached either, so every request goes to the token endpoint. (Current behavior, may change.) | | Subject check | Your authorization server performs it; the console has no connection check for token endpoints. The server must accept only your own agents' full subjects, or at minimum check that each token's subject starts with your organization's **Subject prefix**. | | Endpoint reuse | A registered address can be connected as a gateway or as an authorization server, not both. A token endpoint stays listed in the **Gateways** table after you remove its authorization server, and frees its place among the 5 registered addresses only when you remove it there too. | ## Testing The console's connection check is the only way to have Anthropic send a token to your gateway before Claude does. There is no way to request a test token for your own use. To test end to end, follow the Verify step on each connection page. ## Related resources * [Identity token reference](/docs/claude-tag/admins/federated-access/token-reference): claims, issuer, keys, and rotation * [Connect a gateway](/docs/claude-tag/admins/federated-access/connect-a-gateway) * [Connect an AWS role](/docs/claude-tag/admins/federated-access/aws) * [Connect a Google Cloud identity](/docs/claude-tag/admins/federated-access/gcp) * [Connect an authorization server](/docs/claude-tag/admins/federated-access/authorization-server) * [Network requirements](/docs/claude-tag/admins/network-requirements): Anthropic's egress range and internet reachability
claude-tag/admins/federated-access/overview New page · 77 lines, new page
# Federated cloud access ## Choose a connection type ## How it works ## Before you begin ## Related resources
A whole new page. There's nothing to diff it against, so here is what it says.
# Federated cloud access > Claude Tag proves its identity to your systems with a short-lived signed token instead of a credential stored in Claude. Learn how the token works and which of the four connection types to use. export const BetaNote = () => <Info>Claude Tag is in public beta. Features and behavior described here may change before general availability.</Info>; <BetaNote /> <Note>Federated connections are managed at [`claude.ai/admin-settings/claude-tag`](https://claude.ai/admin-settings/claude-tag): open **Federated cloud access** in the left navigation. Connecting a gateway, cloud role, or authorization server needs an organization Owner, or an admin with full Claude Tag management permission.</Note> In Slack channels, Claude Tag acts under its own [agent identity](/docs/claude-tag/concepts/agent-identity) rather than as any person. Federated cloud access lets that identity prove itself to your systems with a short-lived, signed identity token instead of a credential you store in Claude. Federated cloud access is in public beta. In the console, you connect your gateway, AWS role, Google Cloud identity, or authorization server under **Federated cloud access** and add it to an [Access bundle](/docs/claude-tag/admins/add-connections) attached to the channels where Claude should use it. Your cloud or gateway administrator configures that system to trust Anthropic's issuer and to check that each token's subject belongs to your organization, and the system then decides what the agent may do. To confirm the connection works, ask Claude in one of those channels to make a small request, then check its reply and your system's logs. Federated cloud access goes one way: Claude proves who it is to your systems. For your workloads proving who they are to the Claude API, see [Workload Identity Federation](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation) on the Claude Developer Platform. Your systems can accept the token in one of four ways. The table below says which to choose; the rest of the page explains what the token is and what to have ready. ## Choose a connection type | Connection type | Who accepts the token | Choose it when | | :------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Gateway** | A service you run. It verifies the token, maps the agent to permissions, and forwards the request to your internal systems with credentials you hold. | You want one entry point in front of internal APIs. The [sample gateway](https://github.com/anthropics/claude-tag-wif-gateway-sample) is a starting point. | | **AWS role** | AWS, through an IAM OIDC identity provider. AWS issues temporary credentials for a role whose trust policy names Anthropic's issuer and your organization. | Claude should call AWS APIs under a role you govern with IAM. | | **Google Cloud identity** | Google Cloud, through a workload identity pool. Google issues an access token for the federated identity, acting as a service account if you name one. | Claude should call Google Cloud APIs under an identity you govern with IAM. | | **Authorization server** | Your OAuth 2.0 authorization server. It accepts the token as a JWT bearer grant (RFC 7523) and returns an access token for your APIs. | Your APIs are already protected by your own OAuth server and you'd rather issue its tokens than run a gateway. | In every case the system on your side decides what the agent may do in your systems. Each connection type has its own setup page: [Connect a gateway](/docs/claude-tag/admins/federated-access/connect-a-gateway), [Connect an AWS role](/docs/claude-tag/admins/federated-access/aws), [Connect a Google Cloud identity](/docs/claude-tag/admins/federated-access/gcp), and [Connect an authorization server](/docs/claude-tag/admins/federated-access/authorization-server). ## How it works 1. When a request from Claude's sandbox needs one of your systems, [Agent Proxy](/docs/claude-tag/concepts/agent-identity#agent-proxy) matches it by destination to a federated connection in one of the channel's Access bundles. Until an admin connects a system in **Federated cloud access** and adds it to a bundle attached to the channel, nothing matches and no token is issued for Claude's requests. 2. Anthropic issues an identity token. The token is a JSON Web Token (JWT) signed by Anthropic and valid for 10 minutes. Its subject names your organization and the agent, in the form `wimse://identity.anthropic.com/org/<your organization ID>/agent/<agent ID>`, and its audience names the destination. Claude reuses one token for a session's requests to the same gateway for about five minutes, or until the gateway answers 401, and then requests a new one. The other connection types use a token once, in an exchange. 3. Your side accepts the token. A gateway verifies it directly. AWS or Google Cloud exchanges it for a short-lived cloud credential. Your authorization server exchanges it for an access token. Agent Proxy attaches the result to Claude's request, or signs the request with it for AWS, and forwards the request. The model and the sandbox are never given the token or the credential that comes back. Whichever system accepts the token checks five things: * **Signature**, against the public keys Anthropic publishes, and **issuer**. Together these prove Anthropic issued the token. * **Audience**. This proves the token was issued for the destination it's presented to: your gateway, your authorization server, your Google Cloud provider, or AWS. * **Expiry**. This proves the token is fresh. * **Subject**. This is what names your organization. Every Claude Tag organization's tokens come from the same issuer, and every organization's AWS tokens share the same audience, so the first four checks can pass for a token that belongs to someone else. Every connection type therefore requires a subject check. The strongest form accepts only the exact subjects of your own agents. The minimum form requires the subject to start with your **Subject prefix**, `wimse://identity.anthropic.com/org/<your organization ID>/agent/`, including the `/agent/`; a gateway, authorization server, or Google Cloud attribute condition can pin `iss` and `tenant` instead, since `tenant` carries the same organization ID. The console shows the issuer, the signing-key location, and your **Subject prefix** with copy buttons, and each setup page says where they go. The [identity token reference](/docs/claude-tag/admins/federated-access/token-reference) lists every value and claim and [compares the two forms of the subject check](/docs/claude-tag/admins/federated-access/token-reference#authorize-on-the-subject). Anthropic stores no long-lived credential for your systems, and each call carries a short-lived signed token, so there is no key of yours to rotate or leak. Anthropic rotates its own signing keys, and the [token reference](/docs/claude-tag/admins/federated-access/token-reference#key-rotation) says how a verifier follows them. To cut off access, remove the connection in the console. These lifetimes then apply: | What | How long it lasts | | :--------------------------------------------- | :------------------------------------------------------------------------------------------------------------------- | | A removed connection | Claude stops using a removed gateway at once, and a removed cloud role or authorization server within about a minute | | An identity token already issued | 10 minutes from when it was issued | | AWS credentials already exchanged | 1 hour, the role session length | | A Google Cloud credential already exchanged | As long as Google Cloud issued it for | | An access token from your authorization server | The `expires_in` your server returned | Anthropic doesn't review your gateway, trust policy, or authorization server. When you connect a gateway, the console offers a connection check that confirms the gateway rejects a token whose subject isn't your organization. The other connection types have no check in the console, so you verify them yourself with the steps on each setup page. ## Before you begin * **Federated cloud access** appears in the console's left navigation. It's missing for organizations whose compliance configuration excludes federated cloud access. * An organization Owner, or an admin with full Claude Tag management permission, makes the connection in the console. * Your cloud or gateway administrator configures the system on your side: the gateway operator, your AWS or Google Cloud IAM administrator, or your authorization server's operator. Each setup page lists the values they configure. * An [Access bundle](/docs/claude-tag/admins/add-connections) is attached to the [scope](/docs/claude-tag/concepts/glossary#scope) of the channels where Claude should use the connection. A connection can be in only one bundle, so to use a connection in several places, attach that bundle to each scope. Federated connections work in Slack channels, where Claude acts under your organization's agent identity. They don't work in direct messages, which run under [the individual's own account](/docs/claude-tag/concepts/agent-identity#direct-message-channels). ## Related resources * [How agent identity works](/docs/claude-tag/concepts/agent-identity): the identity these tokens represent, and how Agent Proxy attaches credentials * [Connect a gateway](/docs/claude-tag/admins/federated-access/connect-a-gateway): verify the token at a service you run * [Connect an AWS role](/docs/claude-tag/admins/federated-access/aws): the IAM OIDC provider and trust policy * [Connect a Google Cloud identity](/docs/claude-tag/admins/federated-access/gcp): the workload identity pool, provider, and attribute condition * [Connect an authorization server](/docs/claude-tag/admins/federated-access/authorization-server): accept the token as a JWT bearer grant * [Identity token reference](/docs/claude-tag/admins/federated-access/token-reference): every claim, the lifetime, and key rotation * [Limits](/docs/claude-tag/admins/federated-access/limits): counts, lengths, lifetimes, and unsupported configurations * [Troubleshoot federated cloud access](/docs/claude-tag/admins/federated-access/troubleshooting): console messages, blocked requests, and rejections in your logs
claude-tag/admins/federated-access/token-reference New page · 153 lines, new page
# Identity token reference ## Issuer and signing keys ### Key rotation ## Lifetime ## Subject ### Authorize on the subject ## Audience ## Claims ### Example payload ## Verify a token ## Related resources
A whole new page. There's nothing to diff it against, so here is what it says.
# Identity token reference
> The claims, issuer, signing keys, lifetime, and subject format of the identity token Claude Tag presents to a gateway, cloud provider, or authorization server.
export const BetaNote = () => <Info>Claude Tag is in public beta. Features and behavior described here may change before general availability.</Info>;
<BetaNote />
When Claude calls a system you connected through Federated cloud access, it proves who it is with a signed identity token instead of a stored credential. The token is a JSON Web Token (JWT) that names your organization and the agent making the request. A gateway you run receives it in the `Authorization: Bearer` header and verifies it directly. AWS, Google Cloud, or your authorization server receives it in a token exchange and returns one of its own credentials.
This page lists what the token contains so the engineer who configures the verifying side can pin the right values. For setup steps, see [Connect a gateway](/docs/claude-tag/admins/federated-access/connect-a-gateway), [Connect an AWS role](/docs/claude-tag/admins/federated-access/aws), [Connect a Google Cloud identity](/docs/claude-tag/admins/federated-access/gcp), or [Connect an authorization server](/docs/claude-tag/admins/federated-access/authorization-server).
## Issuer and signing keys
| Item | Value |
| :----------------------------------------- | :------------------------------------------------------------------------------------------------ |
| Issuer (`iss`) | `https://identity.anthropic.com/agents`. Match it exactly, including the `/agents` path. |
| OpenID Connect (OIDC) discovery document | `https://identity.anthropic.com/agents/.well-known/openid-configuration` |
| Signing keys, as a JSON Web Key Set (JWKS) | `https://identity.anthropic.com/agents/jwks.json`, the `jwks_uri` named in the discovery document |
| Signing algorithm | ES256 only. Reject any other `alg`, including `none`. |
Both documents are public and need no authentication to fetch. One issuer serves every Claude Tag organization, so the issuer and signature prove only that Anthropic issued the token. The [subject](#subject), or the `tenant` claim, is what ties a token to your organization.
### Key rotation
Signing keys rotate. If you run the verifier yourself, select the key by the token's `kid` header and refetch the JWKS when you see a `kid` you don't know, before rejecting the token. Most JWKS libraries do this by default. Don't pin a single key. AWS and Google Cloud manage their own key caches.
## Lifetime
| Claim | Value |
| :---- | :---------------------------------------------------------------------------------------- |
| `iat` | When the token was issued, in seconds since the Unix epoch |
| `nbf` | 15 seconds before `iat` (current behavior, may change). Libraries check it automatically. |
| `exp` | 10 minutes (600 seconds) after `iat` |
| `jti` | A unique ID for this token |
Allow up to 60 seconds of clock skew when you check `exp`, and treat `exp` as the earliest moment a token may stop working rather than an exact cutoff; cloud providers apply their own grace.
Tokens can't be revoked before they expire. There is no revocation list or introspection endpoint. When you remove a gateway in the console, Claude stops using it at once, and a token issued before the removal stays valid until it expires, within 10 minutes. When you remove a cloud role or authorization server, Claude stops using it within about a minute, and a credential from an earlier exchange stays valid with AWS, Google Cloud, or your server until it expires, held only by Agent Proxy, never by Claude's sandbox.
Claude reuses one token for a session's requests to the same gateway for about five minutes, half the token's lifetime, or until the gateway answers 401, and then requests a new one (current behavior, may change). A gateway therefore sees the same `jti` on many requests, so don't treat a repeated `jti` as a replay. AWS, Google Cloud, and an authorization server each see a token once per exchange.
## Subject
The `sub` claim names one agent in one organization:
```text theme={null}
wimse://identity.anthropic.com/org/<your organization ID>/agent/<agent ID>
```
* The organization ID starts with `org_` and the agent ID with `cagt_`. Both use only letters, digits, `_`, and `-`, so neither can contain `/` or `:`.
* The **Connect a gateway**, **Connect an AWS role**, **Connect a Google Cloud identity**, and **Connect an authorization server** dialogs show your organization's **Subject prefix**, `wimse://identity.anthropic.com/org/<your organization ID>/agent/`. Every one of your agents' subjects starts with this prefix.
* An agent belongs to one Slack channel. Deleting and recreating a channel creates a new agent with a new ID. The console doesn't show agent IDs; a verifier learns full subjects from the tokens it receives or from your cloud provider's logs.
* The console's connection check for a gateway presents a token for a reserved test agent in your organization, shown in the **Connect a gateway** dialog as the **Control subject**. Your gateway must answer that token with a 2xx status so the check can pass, and must grant that subject no access. See [Connect a gateway](/docs/claude-tag/admins/federated-access/connect-a-gateway).
The `wimse://` form follows the IETF WIMSE working group's workload identifier specification.
### Authorize on the subject
A token with a valid signature, issuer, audience, and expiry can still belong to another organization, because one issuer serves every Claude Tag organization and every organization's AWS tokens share one audience. Only the subject, or the `tenant` claim, says which organization a token belongs to, so every verifier, trust policy, and attribute condition must check it. Write the check in one of two forms, strongest first:
* **Pin the exact subjects.** Accept only the full subjects of your own agents. This is the strongest form, so use it whenever your use case allows. You update the rule when a Slack channel is deleted and recreated, because the new channel's agent has a new ID, and a gateway's list must also include the **Control subject**.
* **Require your organization.** If keeping a list of exact subjects isn't practical, require that `sub` start with your **Subject prefix**, including the `/agent/`, or pin `iss` together with `tenant`, which carries the same organization ID. This is the minimum, and it accepts every agent in your organization, including agents in channels created later.
## Audience
The `aud` claim is a JSON array with one element. Use your library's audience option rather than comparing the raw claim text; some libraries print a one-element array as a bare string.
| Where the token goes | `aud` |
| :---------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| A gateway you connected | The HTTPS address you registered, which the console accepts only as a bare host on the standard port and stores in lowercase, for example `https://gateway.example.com` |
| AWS | `sts.amazonaws.com` |
| Google Cloud | Your workload identity provider's full resource name, for example `//iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/claude/providers/agents` |
| An authorization server | Your server's issuer identifier as you entered it when connecting the server (an HTTPS URL on the token endpoint's host), for example `https://auth.example.com`, or the token endpoint URL exactly as registered, for example `https://auth.example.com/oauth2/token`, if you left the issuer identifier empty |
The audience identifies the destination, not your organization; every organization's AWS tokens share `sts.amazonaws.com`. Always check the [subject](#subject) too.
## Claims
These are the claims a token carries.
| Claim | Value |
| :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `iss` | `https://identity.anthropic.com/agents` |
| `sub` | The agent's subject; see [Subject](#subject) |
| `aud` | One-element array; see [Audience](#audience) |
| `iat`, `nbf`, `exp` | Issued-at, not-before, and expiry times; see [Lifetime](#lifetime) |
| `jti` | Unique token ID |
| `tenant` | Your Claude organization ID, the same value as the subject's `org/` segment. Together with `iss`, this is the pair a relying party pins to trust tokens from one organization. Not your cloud or identity provider's tenant ID. |
| `agent_id` | The agent ID, the same value as the subject's `agent/` segment |
| `profile_id` | The ID of the Access bundle the connection belongs to, starting with `capp_`. Informational. |
| `platform` | `slack` when the request came from Slack. Present whenever `slack_workspace_id` is. |
| `slack_workspace_id` | The ID of the Slack workspace Claude is acting in. Present when the request came from a Slack workspace your organization owns. |
| `slack_channel_id` | The ID of the Slack channel Claude is acting in. Present whenever `slack_workspace_id` is and Claude is acting in one channel rather than a whole workspace. |
Tokens may carry additional claims Anthropic uses internally for audit; ignore any claim not listed here and never base an authorization decision on it.
Anthropic sends the token only to the destinations you connect in **Federated cloud access**. When the request comes from Slack, the `slack_workspace_id` and `slack_channel_id` claims carry your Slack workspace and channel IDs to that destination along with your organization and agent IDs.
Authorize on `sub`, as described under [Authorize on the subject](#authorize-on-the-subject). A gateway or authorization server, which can read every claim, can use `tenant` and `agent_id` instead, because they repeat the subject's two parts. An AWS trust policy matches on `sub` and `aud` only; a Google Cloud attribute condition can read `sub` or `tenant`. The token carries no claims about the person behind the request, and no `groups`, `roles`, or `scope` claims. A rule that needs `slack_workspace_id` or `slack_channel_id` should refuse a token that lacks them.
<Note>Anthropic may add claims to the token. A verifier must ignore claims it doesn't recognize and must never depend on a claim not listed here being present.</Note>
### Example payload
The decoded payload of a token sent to a gateway registered as `https://gateway.example.com`, for a request from a Slack channel, with made-up IDs. Opaque claims are left out.
```json theme={null}
{
"iss": "https://identity.anthropic.com/agents",
"sub": "wimse://identity.anthropic.com/org/org_01Hx7rQkPzT9sN3mVbJw2eYd/agent/cagt_01Mz4kVnXr8TqWb2pLsJ7hYe",
"aud": ["https://gateway.example.com"],
"iat": 1756600000,
"nbf": 1756599985,
"exp": 1756600600,
"jti": "MX4KT2R7WBH5QZ3NDJ6PVA25FC",
"tenant": "org_01Hx7rQkPzT9sN3mVbJw2eYd",
"agent_id": "cagt_01Mz4kVnXr8TqWb2pLsJ7hYe",
"profile_id": "capp_01Qw9tHnKj5Rz3mXb7PvL2cY",
"platform": "slack",
"slack_workspace_id": "T01HX7RQKPZT",
"slack_channel_id": "C01MZ4KVNXRT"
}
```
## Verify a token
Use a maintained JWT or OIDC library for your language and confirm it performs all five checks. Most libraries check issuer and audience only when configured to.
1. **Signature**: verified against a key from the JWKS, ES256 only.
2. **Issuer**: exactly `https://identity.anthropic.com/agents`.
3. **Audience**: the value registered for your gateway, cloud provider, or authorization server.
4. **Expiry**: `exp` is in the future, allowing up to 60 seconds of clock skew.
5. **Subject**: `sub` is one of your own agents' full subjects, or at minimum starts with your organization's **Subject prefix** (or `tenant` is your organization ID). Libraries don't do this one for you.
Reject the token if any check fails, and answer with a generic 401 that doesn't echo the token.
To read a captured token's claims while debugging, decode its middle segment. JWT payloads are base64url-encoded, so a plain `base64 -d` often fails:
```bash theme={null}
python3 -c 'import base64,json,sys; p=sys.argv[1].split(".")[1]; print(json.dumps(json.loads(base64.urlsafe_b64decode(p + "=" * (-len(p) % 4))), indent=2))' "$TOKEN"
```
Decoding doesn't verify anything. Log the subject and your decision, never the token itself.
## Related resources
* [Connect a gateway](/docs/claude-tag/admins/federated-access/connect-a-gateway): verify the token yourself at a service you run
* [Connect an AWS role](/docs/claude-tag/admins/federated-access/aws): the trust policy that pins these values
* [Connect a Google Cloud identity](/docs/claude-tag/admins/federated-access/gcp): the attribute condition that pins these values
* [Connect an authorization server](/docs/claude-tag/admins/federated-access/authorization-server): accept the token as a JWT bearer grant
* [Limits](/docs/claude-tag/admins/federated-access/limits): lengths, counts, and lifetimes in one place
* [Sample gateway](https://github.com/anthropics/claude-tag-wif-gateway-sample): a Python gateway that verifies the token and pins subjects exactly or by organization, with offline tests
claude-tag/admins/federated-access/troubleshooting New page · 345 lines, new page
# Troubleshoot federated cloud access ## Messages in the console ### The check didn't pass ### Removing and reconnecting a gateway ## Errors Claude reports in the thread ### request blocked: this credential only works in channel sessions, not personal ones ### request blocked: this credential's audience isn't registered as a gateway for this organization ### request blocked: Google (gcp) credentials aren't enabled for this organization ### request blocked: this credential has restrict\_credential\_minting set, so Google's credential-minting endpoints are refused ### request blocked: this Google credential only works for requests to Google API hosts ### request blocked: this credential's allowed hosts include its own token endpoint ### credential injection temporarily unavailable; retry the request ### injection failed ### The cloud API answers 403 after a successful exchange ## Rejections in your own logs ### Your gateway rejects every token ### Your gateway sees the same token ID on many requests ### Your gateway, trust policy, or IAM binding pins a full agent subject ### AWS refuses AssumeRoleWithWebIdentity ### Google Cloud refuses the token exchange ### Your authorization server rejects the grant ## Contact Anthropic ## Related resources
A whole new page. There's nothing to diff it against, so here is what it says.
# Troubleshoot federated cloud access
> Errors from Claude Tag's federated cloud access and what fixes each: console dialog messages, requests Claude reports as blocked or failed, and rejections your gateway, AWS, Google Cloud, or authorization server records.
export const BetaNote = () => <Info>Claude Tag is in public beta. Features and behavior described here may change before general availability.</Info>;
<BetaNote />
<Note>Federated connections are managed at [`claude.ai/admin-settings/claude-tag`](https://claude.ai/admin-settings/claude-tag): open **Federated cloud access** in the left navigation. Changing them needs an organization Owner, or an admin with full Claude Tag management permission.</Note>
This page covers what goes wrong after you connect a gateway, AWS role, Google Cloud identity, or authorization server through **Federated cloud access**. It's organized by where the problem shows up: a message in a console dialog, an error Claude reports in the thread, or a rejection in your own logs. The token terms used below are explained on the [identity token reference](/docs/claude-tag/admins/federated-access/token-reference).
First confirm two things that have nothing to do with federation:
* The connection is in an [Access bundle attached to the channel's scope](/docs/claude-tag/admins/attach-to-scope#attach-the-bundle). For a gateway, the scope's custom instructions also [name the gateway's address](/docs/claude-tag/admins/federated-access/connect-a-gateway#let-agents-reach-the-gateway), so Claude knows the gateway exists.
* You tested in a new thread. A thread already running isn't told about a connection added after it started; ask Claude for the service by name, or send [`@Claude !restart`](/docs/claude-tag/users/commands#restart-a-stuck-or-wrong-context-session) at the channel's top level.
If Claude reports that a host isn't allowed before any request is sent, see [Claude says a host isn't allowed](/docs/claude-tag/admins/troubleshooting#claude-says-a-host-isn%E2%80%99t-allowed-or-it-can%E2%80%99t-reach-the-internet).
## Messages in the console
Most dialog messages say what to do. The table adds what the message doesn't. The one message that needs more, "The check didn't pass", has its own entry below the table, followed by what removing and reconnecting a gateway does.
| Message | What it means | Do this |
| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "The check can't run right now. Try again later, or skip the check and record why." | Anthropic couldn't produce the test tokens for the connection check. The problem is on Anthropic's side, not your gateway's. | Wait a few minutes and click **Run check and connect** again. If the message persists, select the **Skip the check** option, enter a **Reason for skipping**, and click **Connect without the check**; remove and reconnect the gateway later to record a passed check. |
| "Too many checks in a short time." followed by how long to wait | Your organization ran the connection check too many times in quick succession. The limit counts every admin in the organization. Entering an address that is already registered runs the check again and counts too, unless the **Skip the check** option is selected. | Wait the time the message names. To add an existing gateway to a bundle, click **Add to bundle** in its row of the **Gateways** table instead of entering its address again. |
| "Too many attempts in a short time." in the **Connect an authorization server** dialog | A general request limit, not the connection check; registering a token endpoint never runs the check. | Wait the time the message names and try again. |
| "Connecting a gateway needs full Claude Tag management permission. Ask an organization owner." or "This needs full Claude Tag management permission. Ask an organization owner." | Your account can't change federated connections. Channel managers, and admins whose Claude Tag permission covers specific channels only, can't connect a gateway, cloud role, or authorization server. | Ask an organization Owner, or an admin with full Claude Tag management permission, to make the connection from their own account. |
| A dialog message containing "isn't enabled for your organization yet", or **Federated cloud access** is missing from the left navigation | Federated cloud access isn't available to organizations whose compliance configuration excludes it. The navigation item is also hidden from channel managers and from admins whose Claude Tag permission covers specific channels only, because connecting a system needs full Claude Tag management permission. | Ask an organization Owner, or an admin with full Claude Tag management permission, to open the page. If it's missing for them too, your organization's compliance configuration excludes the feature. |
| "This organization has reached its limit of 5 gateways. Remove one to connect another." or, in the **Connect an authorization server** dialog, "…limit of 5 registered gateways, which includes token endpoints." | An organization can register 5 addresses. A token endpoint is registered the same way as a gateway, so it counts toward the same 5 and appears in the **Gateways** table marked "Used by a connected authorization server. Manage it from the Authorization servers section." An address is either a gateway or a token endpoint in your organization, not both. | In the **Gateways** table, click **Remove** in the row of a gateway you no longer use. To free a token endpoint's row, click **Remove** in the server's row of the **Authorization servers** table first, then remove the endpoint from the **Gateways** table. See [Removing and reconnecting a gateway](#removing-and-reconnecting-a-gateway). |
| "This gateway is already registered. Close this dialog and pick it from the list to add it to a bundle." | The address is already registered in your organization, and the dialog couldn't load its row to continue. This message is rare: entering a registered address normally runs the connection check again without changing the stored result, then moves on to the bundle step. | Click **Cancel**, then click **Add to bundle** in the gateway's row of the **Gateways** table. |
| "`<address>` is already in the bundle `<bundle>`. Assign that bundle to a channel to use the gateway there.", "This role is already connected in the bundle `<bundle>`.", or "This token endpoint is already connected in the bundle `<bundle>`." | A gateway, AWS role, or token endpoint can be connected in only one Access bundle, and this one already is. | To use the connection in more channels, [attach that bundle to each scope](/docs/claude-tag/admins/attach-to-scope#attach-the-bundle) instead. To move it, in **Access bundles**, open the bundle's **Credentials** tab, open the **⋮** menu on the connection's row, and choose **Delete**. Then add it to the new bundle: **Add to bundle** in the gateway's row of the **Gateways** table, or the connect dialog again for the other types. |
| "`<name>` already covers `<host>` in this bundle, so Claude would never use this connection for the hosts they share. Change the hosts or choose another bundle." in the **Connect a Google Cloud identity** dialog | Another Google Cloud connection in the bundle you chose already has that host under **Allowed hosts**, whatever its provider or service account. Claude uses the first connection in a bundle whose hosts match a request, so the new connection would never be used for the shared host. A wildcard such as `*.googleapis.com` covers every subdomain but not `googleapis.com` itself. The dialog won't connect until the overlap is gone. | Remove the shared host from the new connection's **Allowed Google hosts**, or choose another bundle. To give the host to the new connection instead, first narrow the existing one: in **Access bundles**, open the bundle's **Credentials** tab, open the **⋮** menu on the connection's row, choose **Edit**, and change **Allowed hosts**. |
| "Couldn't connect the gateway. Try again.", "Couldn't add the gateway to the bundle.", "Couldn't connect the role. Try again.", "Couldn't connect the identity. Try again.", "Couldn't register the authorization server. Try again.", or "Couldn't connect the authorization server. Try again." | The request failed for a reason the dialog doesn't name, most often a temporary one. | Try once more. If the message persists, contact your Anthropic account team with the details under [Contact Anthropic](#contact-anthropic). |
| "The issuer URL must be an https URL on the same host as the token endpoint. Leave it empty to use the token endpoint as the audience." in the **Connect an authorization server** dialog | The **Issuer URL** value must be an HTTPS URL on the same host as the token endpoint, or empty. The token is only ever presented to that server, so its audience must name that server. | Enter the issuer identifier your authorization server uses, on the token endpoint's host, or clear the field to use the token endpoint as the audience. |
| "This token endpoint is already connected. Manage it from the Authorization servers section." in the **Connect an authorization server** dialog | An authorization server with this token endpoint is already connected in one of your organization's Access bundles, and a server can be connected only once. The dialog checks this before it registers anything. | To use the server in more channels, [attach its bundle to each scope](/docs/claude-tag/admins/attach-to-scope#attach-the-bundle). To connect it again, remove it first: in the **Authorization servers** table, click **Remove** in the server's row. |
| "That address is already connected as a gateway. Enter your authorization server's own addresses, or remove the gateway first." in the **Connect an authorization server** dialog | The token endpoint, or the **Issuer URL** value, is the address of a gateway connected in one of your organization's Access bundles. One address can't be both, because a token sent to the gateway could be replayed to the server as a grant. | Enter the token endpoint and issuer identifier your authorization server publishes. To use that address for the server instead, remove the gateway first: in **Access bundles**, open the bundle that holds the gateway, open its **Credentials** tab, open the **⋮** menu on the gateway's row, and choose **Delete**. Then, in the **Gateways** table under **Federated cloud access**, click **Remove** in the gateway's row. |
| "That address is registered by a connected authorization server. Enter your gateway's address, or remove the server first." in the **Connect a gateway** dialog | The address you entered is a connected authorization server's token endpoint or audience, for example a server whose **Issuer URL** is the bare host `https://auth.example.com`. One address can't be both, because a token sent to the gateway could be replayed to that server as a grant. | Enter the host your gateway answers on. To use that address for a gateway instead, remove the server first: in the **Authorization servers** table, click **Remove** in the server's row. |
| "That address is already a connected authorization server's audience. Enter this server's own issuer URL." in the **Connect an authorization server** dialog | The **Issuer URL** value (or the token endpoint, when **Issuer URL** is empty) is already another connected authorization server's audience or token endpoint. Two servers can't share an audience, because a token minted for one would be valid at the other. | In the **Issuer URL** field, enter the issuer identifier this server publishes. If the other server holds this identifier by mistake, remove that server first: in the **Authorization servers** table, click **Remove** in its row, then connect it again with its own issuer URL. |
| "The address is too long. Issuer URLs have at most 256 characters." under the **Issuer URL** field of the **Connect an authorization server** dialog | The **Issuer URL** field accepts at most 256 characters, the same limit as the **Token endpoint** field. | Check that the field holds only the issuer identifier, for example `https://auth.example.com`, and not a longer value pasted by mistake. |
| "Couldn't check the addresses against your gateways and servers. Close this dialog and try again." in the **Connect an authorization server** dialog, or "Couldn't check the address against your authorization servers. Close this dialog and try again." in the **Connect a gateway** dialog | Before it registers an address, each dialog loads your organization's existing connections to check that the address doesn't clash with a connected gateway or authorization server. That list didn't load, and the dialog doesn't register an address it couldn't check. | Close the dialog and open it again. If the message persists, reload the page, then contact your Anthropic account team with the details under [Contact Anthropic](#contact-anthropic). |
| An address-field message such as "Enter only the host, like [https://gateway.example.com](https://gateway.example.com), with no path, port or trailing slash.", "Enter a host name, not an IP address.", "That is an Anthropic address. Enter your own gateway's host name.", "That host name only works inside a private network. Enter a host name that is reachable from the internet.", or "That host is reserved for cloud token exchange. Enter your own gateway's host name." | A gateway address is an HTTPS host only, with a domain name of at least two labels. A token endpoint may have a path, but no port, query, fragment, or sign-in details. Neither can be an IP address, a private-network name, an Anthropic-owned host, or a host cloud providers use for token exchange. | Enter the public address the service answers on, for example `https://gateway.example.com` or `https://auth.example.com/oauth2/token`. The console can't register a private address even with the check skipped. |
### The check didn't pass
**What you see**
The **Connect a gateway** dialog shows "The check didn't pass. Claude couldn't reach the gateway, or the gateway didn't reject a token whose subject isn't your organization while accepting one that is. Fix the gateway and run the check again, or skip the check and record why."
**What it means**
The connection check sent two requests to your gateway and didn't get the two answers it needs. The gateway must reject a token whose subject isn't your organization, and it must accept a token for your **Control subject**. The console shows this one message for every failed check, so it doesn't say which request failed. If this was a new address, nothing was registered.
**How to resolve**
The check sends an empty `POST` to the address itself, with nothing added after the host, twice. Work through the causes in order.
| Check | What to do |
| :-------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Claude can reach the address from the internet over HTTPS | Confirm the host resolves publicly, the TLS certificate is valid, and the gateway isn't behind a VPN. |
| An empty `POST` to the address itself is answered directly | The check doesn't follow redirects, and any status other than the two expected ones fails it, including a 503 from a gateway that couldn't fetch the signing keys. |
| The token whose subject isn't your organization gets 401 or 403 | If the gateway answered 2xx, the subject check is missing or wrong. |
| The token for the **Control subject** gets 2xx | A gateway that rejects every token is usually missing the control subject, or has a wrong issuer, audience, or key setting. With the sample gateway, add the **Control subject** as a `principals` entry with `allowed_services: []` in `config.yaml`. |
A 503 from the gateway usually means it can't reach `https://identity.anthropic.com` to fetch the keys. For a gateway that rejects every token, [Your gateway rejects every token](#your-gateway-rejects-every-token) lists each setting to compare. If you deployed [Anthropic's sample gateway](https://github.com/anthropics/claude-tag-wif-gateway-sample), its `config.yaml` must carry your real organization ID in the control-subject entry.
If the gateway can't be fixed right away, select the **Skip the check** option, enter a **Reason for skipping**, and click **Connect without the check**. To run the check later, remove the gateway and connect it again; see [Removing and reconnecting a gateway](#removing-and-reconnecting-a-gateway).
### Removing and reconnecting a gateway
In the **Gateways** table, click **Remove** in the gateway's row. Claude stops using the gateway at once. A connection that used the gateway stays in its Access bundle but stops working, and Claude reports [request blocked: this credential's audience isn't registered as a gateway for this organization](#request-blocked-this-credential%E2%80%99s-audience-isn%E2%80%99t-registered-as-a-gateway-for-this-organization) until the gateway is registered again.
To reconnect, click **Connect a gateway** in the **Gateways** section and enter the same address. Registering the address restores the existing connection, which is still in the bundle, so don't add it to the bundle again; the dialog refuses if you try.
## Errors Claude reports in the thread
When a request from a channel can't be sent with a federated credential, it fails with an HTTP status and a one-line reason, which Claude usually quotes. Reasons with HTTP 403 and 502 end with the connection's name in parentheses, for example `("gateway.example.com")`. The two 503 reasons don't name the connection.
Messages that begin "request blocked" come with HTTP 403. The request was refused on purpose, and retrying won't help. A 503 is temporary. A 502 usually means AWS, Google Cloud, or your authorization server refused the token exchange. A response from your gateway or from the cloud API itself reaches Claude as is, so those show as whatever status the other side returned.
### request blocked: this credential only works in channel sessions, not personal ones
**What you see**
Claude's request got HTTP 403 with this reason.
**What it means**
Federated connections work only in Slack channels, where Claude acts under your organization's [agent identity](/docs/claude-tag/concepts/agent-identity). The request came from a direct message, or from another session running under a person's own account, which has no agent identity for the token to name.
**How to resolve**
Use the connection from a channel whose scope has the bundle attached. No setting enables it in direct messages.
### request blocked: this credential's audience isn't registered as a gateway for this organization
**What you see**
Claude's request got HTTP 403 with this reason.
**What it means**
The gateway was removed from the **Gateways** table, but its connection is still in an Access bundle. Claude can't get a token for an address that isn't registered.
**How to resolve**
To keep the gateway, register the same address again; see [Removing and reconnecting a gateway](#removing-and-reconnecting-a-gateway). To drop it, in **Access bundles**, open the bundle's **Credentials** tab, open the **⋮** menu on the connection's row, and choose **Delete**.
### request blocked: Google (gcp) credentials aren't enabled for this organization
**What you see**
Claude's request got HTTP 403 with this reason.
**What it means**
A Google Cloud identity is connected in a bundle, but Google Cloud federation is off for your organization.
**How to resolve**
Contact your Anthropic account team with the details under [Contact Anthropic](#contact-anthropic).
### request blocked: this credential has restrict\_credential\_minting set, so Google's credential-minting endpoints are refused
**What you see**
Claude's request got HTTP 403 with this reason.
**What it means**
The Google Cloud identity was connected with **Block requests that mint new credentials** selected, and Claude tried to call a Google endpoint that creates keys, tokens, or other credentials. The block worked as intended.
**How to resolve**
Usually nothing: the block worked. If Claude needs that call, review the identity's IAM permissions first, because the block is a safeguard on top of IAM and not a replacement for it. The setting is chosen when the identity is connected, so in the **Cloud roles** table, click **Remove** in the identity's row, and connect the identity again with the **Block requests that mint new credentials** checkbox cleared.
### request blocked: this Google credential only works for requests to Google API hosts
**What you see**
Claude's request got HTTP 403 with this reason.
**What it means**
Claude tried to send a Google Cloud credential to a host Google doesn't serve. The credential is attached only to `googleapis.com`, its subdomains, and subdomains of `clients6.google.com`.
**How to resolve**
If the target is a Google API, check the host Claude used. If it isn't, the request needs a different connection.
### request blocked: this credential's allowed hosts include its own token endpoint
**What you see**
Claude's request got HTTP 403 with the reason "request blocked: this credential's allowed hosts include its own token endpoint; an admin must remove the token endpoint's host from the allowed hosts".
**What it means**
The authorization server connection's allowed hosts cover the token endpoint's own host, for example through a wildcard such as `*.example.com` that covers `auth.example.com`. The connect dialog refuses this when the connection is created, and so does every later edit of its allowed hosts, so the message isn't expected; the same rule is checked again on every request. The access token your server returns must never be sent back to the server that issued it, so every request with this connection is refused until an admin fixes it.
**How to resolve**
In **Access bundles**, open the bundle's **Credentials** tab, open the **⋮** menu on the connection's row, choose **Edit**, and in the **Edit connection** dialog set **Allowed hosts** to only the APIs Claude calls with the returned token, for example `api.example.com`, with no wildcard that covers the token endpoint's host. If the API and the token endpoint share a host, use a different host for one of them.
### credential injection temporarily unavailable; retry the request
**What you see**
Claude's request got HTTP 503 with this reason, or with "injection capacity exceeded; retry the request".
**What it means**
Something was briefly unavailable. Anthropic's identity service, your cloud provider's token exchange, or your authorization server answered with a server error (5xx) or 429, or timed out, or a failure moments earlier is still being backed off.
**How to resolve**
Ask Claude to retry. If one connection keeps failing this way, check that your authorization server or cloud provider is reachable and healthy, then contact your Anthropic account team with the details under [Contact Anthropic](#contact-anthropic).
### injection failed
**What you see**
Claude's request got HTTP 502 with the reason `injection failed ("<connection name>")`.
**What it means**
Most often, the system Claude's identity token was presented to refused the exchange. AWS refused `AssumeRoleWithWebIdentity`, Google Cloud's token exchange refused the token, or your authorization server answered the grant with an error. Claude's reply doesn't say why; your own logs do.
**How to resolve**
Look up the refusal where it happened and fix the configuration it names.
| Connection | Where to look | Entry |
| :-------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------ |
| AWS role | CloudTrail, the `AssumeRoleWithWebIdentity` event for the role | [AWS refuses AssumeRoleWithWebIdentity](#aws-refuses-assumerolewithwebidentity) |
| Google Cloud identity | Cloud Audit Logs, the Security Token Service API entry for the token exchange and, if you named a service account, the IAM Service Account Credentials API entry | [Google Cloud refuses the token exchange](#google-cloud-refuses-the-token-exchange) |
| Authorization server | Your server's log for the `POST` to the token endpoint | [Your authorization server rejects the grant](#your-authorization-server-rejects-the-grant) |
Allow for log delivery delay before concluding there was no attempt. If your logs show none at the time of the request, the token wasn't issued, and you should [contact Anthropic](#contact-anthropic) with the details listed there. A gateway connection doesn't produce this error. Your gateway's own response reaches Claude, so Claude reports the status your gateway returned, usually 401 or 403; see [Your gateway rejects every token](#your-gateway-rejects-every-token).
### The cloud API answers 403 after a successful exchange
**What you see**
Claude reports a 403 from an AWS or Google Cloud API, with the provider's own error body rather than a reason beginning "request blocked".
**What it means**
The token exchange worked and Claude called the API with the exchanged credential, but the role or identity lacks permission for that action. For Google Cloud, the exchange always requests the `cloud-platform` scope, so IAM alone decides what the credential can do.
**How to resolve**
Grant the IAM permission to the AWS role, the Google Cloud service account, or the federated identity when no service account is named. For AWS, a 403 also makes Claude assume the role again on the next request, so a fix takes effect on the next try.
## Rejections in your own logs
### Your gateway rejects every token
**What you see**
Every request from Claude gets 401 or 403 from your gateway, including the connection check's token for the **Control subject**.
**What it means**
One of the standard checks is configured with the wrong value. Your gateway's log of the failing check is the fastest route; if it logs nothing, work down the list. The values to compare against are shown in the **Connect a gateway** dialog before you enter an address, as described on [Connect a gateway](/docs/claude-tag/admins/federated-access/connect-a-gateway#copy-the-values-and-deploy-the-gateway).
**How to resolve**
| Check | What to confirm |
| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Audience | The `aud` claim is a JSON array with one element, your gateway address exactly as the console stored it: `https://` plus the lowercase host, no path or trailing slash. Use your library's audience option rather than comparing the raw claim to a string. |
| Issuer | Exactly `https://identity.anthropic.com/agents`, including the path. A verifier configured with any other issuer value, such as the bare host, a different path, or a trailing slash, rejects every token, including the connection check's token. |
| Signing keys | Fetched from the JSON Web Key Set (JWKS) named in `https://identity.anthropic.com/agents/.well-known/openid-configuration`. Accept ES256 only. Select the key by `kid`, and refetch the JWKS on an unknown `kid` before rejecting. |
| Time | The token expires 10 minutes after issue (`exp`) and is valid from 15 seconds before issue (`nbf`). Check `exp`, allowing up to 60 seconds of clock skew, and make sure your gateway's clock is right. |
| Subject | The subject check accepts your listed agents' full subjects and the **Control subject**, or at minimum every subject starting with your **Subject prefix**, `wimse://identity.anthropic.com/org/<your organization ID>/agent/`, including the `/agent/`. A list that omits the **Control subject** fails the connection check, and a list that omits an agent rejects that agent's requests. |
### Your gateway sees the same token ID on many requests
**What you see**
Requests within a few minutes of each other carry a token with the same `jti`. A gateway that treats a repeated `jti` as a replay rejects almost everything.
**What it means**
This is normal. Claude reuses one token for a session's requests to the same gateway for about five minutes, or until your gateway answers 401, and then requests a new one. A plain 403 from your gateway doesn't refresh the token. Exchanges are different: AWS, Google Cloud, and an authorization server each see a token once per exchange.
**How to resolve**
Don't do per-request replay detection at a gateway. Rely on the signature, audience, expiry, and subject checks.
### Your gateway, trust policy, or IAM binding pins a full agent subject
**What you see**
One of two things. The connection check passed, but Claude's requests from a channel get 403 from your gateway. Or a gateway mapping, AWS trust policy condition, or Google Cloud IAM binding that matched a full subject ending in `/agent/cagt_...` stopped matching after the Slack channel was deleted and recreated.
**What it means**
Your rule accepts only specific agents. The connection check's **Control subject** is a reserved agent, so a rule listing it passes the check while rejecting real agents. And each channel's agent has its own ID: deleting and recreating a channel creates a new agent, so a pinned subject no longer appears in any token. By default the sample gateway accepts only the subjects listed in its configuration, and it logs the verified subject of each agent it rejects.
**How to resolve**
If you pin exact subjects, keep the list current. Log the verified subject of each rejected request, add each new agent's full subject to your rule (and, for a gateway, the **Control subject** with no access), and update the rule whenever a channel is deleted and recreated. The console doesn't display agent IDs, so your own logs are where you learn them. If keeping the list current isn't practical, accept every subject that starts with your **Subject prefix**, `wimse://identity.anthropic.com/org/<your organization ID>/agent/`, instead, which is the minimum form of the subject check. In the sample gateway, that is an `organization_principals` entry in `config.yaml`.
### AWS refuses AssumeRoleWithWebIdentity
**What you see**
Claude reports `injection failed` with HTTP 502, and CloudTrail shows an `AssumeRoleWithWebIdentity` event for the role with an error code.
**What it means**
STS refused to issue credentials for Claude's token. The trust relationship between your role and Anthropic's issuer isn't right.
**How to resolve**
| CloudTrail error | What to confirm |
| :--------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `InvalidIdentityToken` | The IAM OIDC identity provider's URL is exactly `https://identity.anthropic.com/agents`, with the `/agents` path (AWS displays it without `https://`), and its audience list includes `sts.amazonaws.com`. |
| `AccessDenied` | The trust policy's condition keys start with `identity.anthropic.com/agents:`; the `aud` condition is `StringEquals` on `sts.amazonaws.com`; the `sub` condition matches the token's subject, either `StringEquals` on this agent's full subject or `StringLike` on `wimse://identity.anthropic.com/org/<your organization ID>/agent/*`. `AccessDenied` also appears when the role was deleted or renamed. |
| Any other code | AWS's STS documentation describes it. If the two rows above check out, the token itself is fine. |
AWS credentials are reused for up to an hour for the same agent, so several threads' requests can appear under one CloudTrail session, and a trust policy change takes effect only when those credentials expire or AWS answers a request with 403.
### Google Cloud refuses the token exchange
**What you see**
Claude reports `injection failed ("<connection name>")` with HTTP 502. Google's token exchange rejected the token, or the service account impersonation that follows it was refused. Claude shows this one message for every refusal from Google, so the message doesn't say which check failed.
**What it means**
The workload identity pool's provider or attribute condition doesn't accept the token, or the federated identity can't act as the service account you named.
**How to resolve**
Google records the reason in your Cloud Audit Logs. The Security Token Service API entry covers the token exchange, and, if you named a service account, the IAM Service Account Credentials API entry covers the impersonation. Both are Data Access audit logs, which Google keeps off by default, as described under [Verify the connection](/docs/claude-tag/admins/federated-access/gcp#verify-the-connection). If the logs were on and show no entry at the time of the request, the token wasn't issued; see [injection failed](#injection-failed). Otherwise, work through the checks in order.
| Check | What to confirm |
Cut at 300 lines. The page has the rest.