How to give AI coding agents AWS and Google Cloud access with OIDC instead of stored keys
Published
Summary
A coding agent swaps a 15-minute OIDC token for AWS credentials, with no stored key. Real commands and output, what AWS rejected, and how other agents compare.
A coding agent that deploys code, reads logs, or checks a bucket needs cloud access. The usual way to give it that is to paste an AWS access key or a Google service account file into its environment variables. Then anything the agent runs can read the key, including a bad dependency or instructions hidden in an issue it was asked to fix. If the key leaks, it keeps working until someone notices and rotates it.
OpenID Connect (OIDC) removes the stored key. The agent's machine asks for a signed token that says which organization, environment, and workspace it belongs to. AWS or Google Cloud checks the signature against the issuer's public keys, compares the token with a trust policy you set up once, and returns credentials that expire within the hour. GitHub Actions has worked this way for years, and several cloud coding agents now do too.
How an agent gets AWS credentials without a stored key
01
Agent
Workspace
Asks for a token for one service
replicas identity token --audience sts.amazonaws.com
02
Replicas
api.replicas.dev
Signs a token that lasts 15 minutes
sub: org:…:env:…:workspace:…
03
AWS STS
Your AWS account
Checks the signature, audience and subject
Against the keys at /.well-known/jwks.json and your role’s trust policy
04
Agent
Workspace
Gets temporary credentials for one role
Keys that start with ASIA and expire in 1 hour
In the workspace
A CLI profile that runs the exchange, and no AWS key
In your AWS account, once
An OIDC provider for api.replicas.dev and a role whose trust policy names your organization
Google Cloud and your own APIs follow the same steps, with Google’s STS or your service in step 3.
The steps below run that exchange with Replicas workspace identity and show the real output.
How we tested
An AI agent, Claude Code running in a Replicas workspace, ran every command on this page on November 7, 2026 and wrote the guide. A person at Replicas reviewed it before it was published.
The AWS exchange used our own AWS account and an IAM role we had made earlier to test this feature. The role has no permissions attached, so it can prove who it is and do nothing else. We created no AWS resources for this guide. We had no Google Cloud project to test with, so the Google Cloud exchange is marked as not run. In the output below, IDs, account numbers, and email addresses are replaced with placeholders, and no full token is shown.
Step 1: Get a token and check its signature
Inside a workspace, the replicas CLI asks for a token for one audience, which is the service that will receive it. For AWS, the audience is sts.amazonaws.com:
That took 0.9 seconds. A JWT has three base64url parts: a header, the claims, and a signature. Decoded, the first two were:
exp minus iat is 900 seconds, so the token lasts 15 minutes. AWS trust policies match on sub. The other claims are for services that can read them, such as Google Cloud and your own APIs. The docs describe each one.
Anyone can write JSON that decodes like this, so the claims mean nothing until the signature checks out. The issuer publishes its public keys at fixed addresses:
jwks.json held one 2048-bit RSA key with the same kid as the token. We converted it to PEM and checked the signature with OpenSSL, without any Replicas code:
Changing one character of signed.txt gave Verification failure. AWS, Google, and your own service all run this same check.
Step 2: Trust the issuer in AWS
Someone with IAM access does this once. We didn't repeat it for this guide because the provider and role already existed in our account. AWS's guide covers the console steps. It comes down to two things:
- An IAM OIDC identity provider with the URL
https://api.replicas.devand the audiencests.amazonaws.com. - A role whose trust policy accepts tokens from that provider. This is the trust policy on the role we used, with our IDs replaced and a second pattern for an older token format left out:
For a provider like this, a trust policy can match the token's aud and sub, but not custom claims such as creator_email (AWS). So sub is where you narrow access. Put an environment ID in place of env:* to accept only workspaces from that environment. What the agent can do once it has the role is set by the role's permission policies, as with any role. Ours has none.
Step 3: Exchange the token for AWS credentials
In the workspace, an AWS CLI profile runs the exchange whenever the CLI or an SDK needs credentials:
You can ask the agent to set this up in plain words, or put the command in the environment's start hook so every workspace starts with it. Any agent in the workspace uses the profile the same way, whether it's Claude Code, Codex, or a script, because it's an ordinary AWS CLI profile.
We removed the AWS keys from the shell first, so nothing else could be used:
The first call took 3.0 seconds, including the exchange. The second took 1.4 seconds, because the helper caches the credentials and only exchanges a new token when they have less than 15 minutes left. The cache is a file only the workspace user can read:
Keys that start with ASIA are temporary. Long-lived IAM user keys start with AKIA. These expired one hour after the exchange.
The helper calls STS AssumeRoleWithWebIdentity. You can make the same call yourself, and it needs no AWS credentials:
What AWS accepted and rejected
We then sent tokens and requests that should fail. AWS refused all of them except the expired token, which it accepted for up to five minutes after it expired:
| What we sent | What AWS returned |
|---|---|
A token minted for https://api.example.com instead of sts.amazonaws.com | InvalidIdentityToken |
A real token with sub edited to another organization | InvalidIdentityToken, because the signature no longer matched |
| A token that had expired 2 minutes 20 seconds earlier | New credentials. AWS accepted it |
| The same token, 4 minutes 50 seconds after it expired | New credentials again |
| The same token, 5 minutes 47 seconds after it expired | ExpiredTokenException: Token expired: current date/time 1794040233 must be before the expiration date/time 1794040186 |
A valid token with --source-identity, on a role whose trust policy doesn't allow sts:SetSourceIdentity | AccessDenied |
aws s3 ls with the role's credentials | AccessDenied: no identity-based policy allows s3:ListAllMyBuckets |
The token proves which workspace is calling, and the role decides what that workspace may do. Ours allows nothing, so S3 refused. If you turn on source identity, AWS records the workspace ID on every action in CloudTrail. The role's trust policy has to allow it first, as the sixth row shows.
The expired token surprised us. The "current date/time" in AWS's error was exactly 300 seconds behind the real time, which suggests STS allows five minutes for clock differences. At AWS, a token that lasts 15 minutes can be exchanged for up to 20, and the credentials it returns last another hour. We found no AWS page that documents this window.
Google Cloud (not run end to end)
Google Cloud uses Workload Identity Federation. Someone with IAM access creates a workload identity pool with an OIDC provider for https://api.replicas.dev, maps google.subject to assertion.workspace_id, adds a condition such as assertion.organization_id == '<organization_id>', and grants roles. Unlike AWS, Google's conditions can read any claim, so you can also limit access by environment_id or creator_email. Our docs have the commands.
In the workspace, gcloud and Google's client libraries run a command to get a token whenever they need one. This is the command they run, and what it printed for us:
That is the format Google expects from an executable credential source. We had no Google Cloud project for this test, so we didn't send the token to Google's STS.
Your own API or MCP server
The same token works for any service that can check a JWT. As a stand-in for an internal deploy API, we ran this Node server in the workspace. It has no dependencies, keeps the issuer's keys for 5 minutes, and fetches them again sooner when a token names a key it doesn't have:
We saved it as server.mjs and started it with our organization ID as the only allowed organization:
The agent called it with a fresh token for that audience:
| What we sent | Response |
|---|---|
A token for https://deploys.internal.example | 200 with the workspace, environment, and creator's email |
| No token | 401 Missing token |
A token minted for https://api.example.com | 401 Wrong audience |
A real token with organization_id edited | 401 Invalid signature |
A token with "alg": "none" and no signature | 401 Invalid signature |
| A valid token, with our organization left off the allowlist | 401 Organization not allowed |
| A token that had expired 53 seconds earlier | 401 Expired or not yet valid |
For an MCP server, you don't need the CLI. When you add an HTTP MCP server to a Replicas environment, choose Workspace identity token as its authentication, and Replicas attaches a current token to every request (docs). The server checks it the same way. We didn't test the MCP path for this guide.
How other cloud coding agents get cloud credentials
Every cloud coding agent we checked can store secrets and hand them to the agent's machine. Five of the nine below also issue their own OIDC token, so you can set up keyless access to AWS or Google Cloud the way this guide does, and GitHub Copilot can use GitHub Actions' token. If you use more than one agent, each one with its own issuer needs its own provider and trust policy in your cloud account.
We checked each vendor's own docs on November 7, 2026. Agents are in alphabetical order:
| Agent | Stored secrets | Own OIDC token |
|---|---|---|
| Claude Code on the web | Environment variables, which anyone who uses the environment can read. Network secrets, which Anthropic's proxy adds to requests for hosts you list, so the session never sees them (Anthropic) | Not documented for Anthropic-hosted environments. Self-hosted environments, in beta on Team and Enterprise, run on your machines, where a wrapper script can provision short-lived credentials per session (Anthropic) |
| Codex cloud | Environment variables, and network secrets that a proxy swaps in on HTTPS requests (OpenAI) | Yes, set per environment. OpenAI lists supported services for AWS, Google Cloud, and Azure. RDS and Cloud SQL IAM logins, and Azure Resource Manager, Blob Storage, and Container Registry, are not yet supported (OpenAI) |
| Cursor cloud agents | Secrets as environment variables. Runtime secrets are redacted from transcripts and commits but can still be read in the terminal (Cursor) | Yes. Issuer https://api.cursor.com, tokens last 5 minutes. AWS has a worked example. Google Cloud, Azure, and Vault are listed as compatible (Cursor) |
| Devin | Secrets given to commands as environment variables when needed, scoped to the organization, a person, a repository, or a session (Cognition) | Yes. Issuer https://app.devin.ai, with setup actions for AWS, Google Cloud, Vault, and JFrog. Token lifetime isn't published (Cognition) |
| Factory | Personal and organization secrets, which become environment variables. Not available during environment builds (Factory) | None documented |
| GitHub Copilot cloud agent | Agents secrets, given to the agent as environment variables (GitHub) | Through GitHub Actions. When the agent runs on Actions, its setup steps can request Actions' OIDC token. GitHub documents an Azure login this way (GitHub) |
| Google Jules | Repository environment variables, turned on per task (Google) | None documented |
| Ona | Organization, project, and user secrets (Ona) | Yes. Issuer https://app.gitpod.io, with AWS and Google Cloud guides (Ona). Enterprise plan (Ona) |
| Replicas | Environment variables, which can also sync from Doppler or Infisical (Replicas) | Yes. Issuer https://api.replicas.dev, tokens last 15 minutes. AWS and Google Cloud guides, and MCP servers. Team and Enterprise plans, and trials (Replicas) |
Where Replicas falls short
Workspace identity is only on Team and Enterprise plans and trials. Our tokens last 15 minutes, three times as long as Cursor's 5, and an issued token can't be revoked before it expires. Our docs cover AWS and Google Cloud but not Azure, and we haven't tested Azure.
For an API that only accepts a fixed key, Replicas puts the key in an environment variable the agent can read. Claude Code on the web and Codex cloud can keep that kind of key in a proxy outside the agent's machine, and Replicas has no equivalent yet. The security page lists the controls Replicas does have, by plan.
What OIDC doesn't protect against
Short-lived tokens remove one risk: a long-lived key sitting in the agent's environment. They don't make the agent trustworthy, and they don't limit what it does with access you gave it.
| Risk | Does a short-lived token help? | What to do |
|---|---|---|
| The agent misuses access it was given, for example after reading instructions planted in an issue | No. It can do whatever the role allows | Give the role only what the task needs, read-only where you can. Use a separate role for each environment |
| Credentials are copied out of the workspace during a session | Partly. AWS accepts the token for up to 5 minutes after it expires, and the credentials it returns last an hour. Both work from anywhere until then | If you suspect a leak, revoke the role's active sessions in IAM |
| Anyone who can start a workspace in your organization gets a token that matches an organization-wide trust policy | No | Match one environment in sub, and limit who can use that environment |
| You remove someone's access, but they already have a token | Partly. Replicas stops issuing tokens right away, but a token already issued works until it expires | Archive the workspace to stop new tokens, and revoke the role's sessions in AWS if it matters |
| Data the agent reads goes to its model provider | No | Don't give the role access to data you can't send to your model provider. Our HIPAA guide covers where that data goes |
| A service only accepts a fixed API key | No | That key still lives in the workspace. Scope it and rotate it |
If you're rolling this out across a company, Replicas Enterprise adds dedicated or self-hosted deployment and SCIM provisioning. The workspace identity docs have the full setup for AWS, Google Cloud, MCP servers, and your own APIs.