GitHub Actions Tutorial — OIDC Tokens
OIDC Tokens
OpenID Connect (OIDC) lets your workflows authenticate with cloud providers without storing long-lived credentials. Instead of API keys or access keys stored as secrets, the workflow requests a short-lived token directly from the cloud provider.
Why OIDC?
| Traditional (secrets) | OIDC (tokens) |
|---|---|
| Store AWS access keys as secrets | No stored credentials |
| Keys are long-lived | Tokens expire in minutes |
| Must rotate manually | Auto-rotated every run |
| Risk of key exposure | No keys to expose |
| Works everywhere | Requires cloud provider setup |
How OIDC Works
1. Workflow requests OIDC token from GitHub
↓
2. GitHub issues a JWT with claims:
- repository, branch, workflow, actor
↓
3. Workflow sends JWT to cloud provider
↓
4. Cloud provider validates JWT against GitHub's OIDC endpoint
↓
5. Cloud provider issues short-lived credentials
↓
6. Workflow uses credentials to access resources
AWS — OIDC Authentication
Setup (one-time)
- Create an OIDC identity provider in AWS IAM
- Create an IAM role that trusts the GitHub OIDC provider
- Scope the trust policy to your repo/branch
Workflow
permissions:
id-token: write # required for OIDC
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
aws-region: us-east-1
- name: Deploy
run: aws s3 sync ./dist s3://my-bucket
No AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY stored anywhere.
Azure — OIDC Authentication
Setup (one-time)
- Register an app in Azure AD
- Add federated credentials for your GitHub repo
- Assign roles to the app
Workflow
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Azure login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Deploy
run: az webapp deploy --name myapp --src-path ./dist
GCP — OIDC Authentication
Workflow
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Authenticate to GCP
uses: google-github-actions/auth@v2
with:
workload_identity_provider: 'projects/123/locations/global/workloadIdentityPools/my-pool/providers/my-provider'
service_account: 'my-sa@my-project.iam.gserviceaccount.com'
- name: Deploy
run: gcloud app deploy
OIDC Token Claims
The JWT token GitHub issues contains claims that cloud providers use to authorize access:
| Claim | Example | Use |
|---|---|---|
sub |
repo:owner/repo:ref:refs/heads/main |
Restrict by repo + branch |
repository |
owner/repo |
Restrict by repository |
ref |
refs/heads/main |
Restrict by branch/tag |
environment |
production |
Restrict by environment |
actor |
octocat |
Restrict by user |
workflow |
deploy.yml |
Restrict by workflow |
Trust Policy Example (AWS)
{
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main"
}
}
}
This only allows tokens from the main branch of my-org/my-repo.
Common Mistakes
| Mistake | Fix |
|---|---|
Missing id-token: write permission |
Add permissions: id-token: write to the workflow or job |
| Trust policy too broad | Scope to specific repo + branch, not repo:* |
| Token rejected by cloud provider | Check the trust policy matches the token’s claims exactly |
| OIDC not working in fork PRs | Fork PRs can’t request OIDC tokens (security) |
Quick Reference
| Cloud | Action | Key Input |
|---|---|---|
| AWS | aws-actions/configure-aws-credentials@v4 |
role-to-assume: |
| Azure | azure/login@v2 |
client-id:, tenant-id: |
| GCP | google-github-actions/auth@v2 |
workload_identity_provider: |
| Required permission | id-token: write |
Always needed for OIDC |
← Previous: Environments
Next: Practice Exercises →