GitHub Actions OIDC Authentication
Deploying to a cloud provider requires credentials. Storing long-lived cloud keys as GitHub secrets creates risk: keys leak, expire, and need manual rotation. OpenID Connect, called OIDC, replaces stored keys with short-lived tokens that exist only for the length of a job.
OIDC in Simple Words
Imagine a visitor badge at an office. A permanent master key can open every door forever, and losing it is a disaster. A visitor badge opens specific doors, expires at the end of the day, and the front desk checks identity before issuing it. OIDC works like the visitor badge. GitHub proves who the workflow is, and the cloud issues a temporary pass.
Old Method Versus OIDC
| Feature | Stored Cloud Keys | OIDC |
|---|---|---|
| Lifetime | Months or years | Minutes |
| Rotation | Manual work | Not needed |
| Leak impact | High | Low |
| Scope | Often broad | Limited by repository and branch |
The Handshake
+-------------+ 1. request token +------------------+
| Workflow | -----------------> | GitHub OIDC |
| job | <----------------- | provider |
+-------------+ 2. signed token +------------------+
|
| 3. present token
v
+-------------+ 4. check rules +------------------+
| Cloud | -----------------> | Trust policy |
| provider | <----------------- | (repo, branch) |
+-------------+ 5. approve +------------------+
|
| 6. temporary credentials
v
+-------------+
| Job deploys |
+-------------+What Is Inside the Token
The signed token carries claims, which are facts about the job. The cloud provider reads them to decide whether to trust the request.
| Claim | Example Value |
|---|---|
| sub (subject) | repo:my-org/my-app:ref:refs/heads/main |
| repository | my-org/my-app |
| ref | refs/heads/main |
| environment | production |
| aud (audience) | sts.amazonaws.com |
Workflow Setup
The job needs the id-token: write permission. Without it, GitHub refuses to issue a token.
name: Deploy With OIDC
on:
push:
branches: [ main ]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get temporary AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-deploy-role
aws-region: us-east-1
- name: Check identity
run: aws sts get-caller-identityThe role address contains no secret. Anyone can read it, because the trust policy decides who may use the role.
Cloud Side Setup on AWS
Create the Identity Provider
In IAM, add an OpenID Connect provider with the address https://token.actions.githubusercontent.com and the audience sts.amazonaws.com.
Create a Role With a Trust Policy
The policy limits access to one repository and branch.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:my-org/my-app:ref:refs/heads/main"
}
}
}]
}Attach a permissions policy to the role that grants only the deployment actions the job needs.
Other Cloud Providers
| Provider | Mechanism | Common Action |
|---|---|---|
| Microsoft Azure | Federated credential on an app registration | azure/login |
| Google Cloud | Workload identity federation | google-github-actions/auth |
| HashiCorp Vault | JWT authentication method | hashicorp/vault-action |
Tighten the Trust Policy
A loose policy defeats the purpose. A subject like repo:my-org/* lets every repository in the organization assume the role. Pin the exact repository. Pin a branch or an environment for production roles. Use separate roles for staging and production.
Troubleshooting
- The error "Credentials could not be loaded" often means the
id-token: writepermission is missing. - An access denied message points to a subject mismatch. Compare the policy text with the actual claim.
- Pull request workflows carry a different subject, such as
repo:my-org/my-app:pull_request. Add that value to the policy only when needed.
Benefits in Practice
Teams delete cloud secrets from repository settings, remove rotation reminders, and shrink the damage from any leak. Audit logs in the cloud show exactly which repository and branch assumed each role.
