Implementing OIDC Authentication: From GitHub Actions to AWS - A Practical Guide

What You'll Learn

  • The fundamentals of OIDC authentication

  • How OIDC differs from OAuth 2.0

  • Setting up OIDC with GitHub Actions and AWS

  • Security best practices and troubleshooting


Cloud Authentication's Leap Forward: The OIDC Advantage

Deploying to AWS meant managing long-term access keys in your CI/CD pipeline. Those days introduced constant security concerns: key rotation, secure storage, and the ever-present risk of credential leaks.

Enter OpenID Connect (OIDC) - a game-changing authentication protocol that's transforming how we handle cloud access. By eliminating the need for stored credentials and introducing short-lived tokens, OIDC is setting new standards for secure cloud authentication.

Understanding OIDC: Beyond OAuth 2.0

OIDC builds upon OAuth 2.0's foundation, but with a major difference:

While OAuth 2.0 determines what you can access, OIDC adds the vital component of who you are.

This distinction matters because modern cloud deployments need both authentication (identity verification) and authorization (access control).

Key Advantages of OIDC

  1. Enhanced Security

    • No stored credentials

    • Automatic token expiration

    • Cryptographically signed tokens (JWT)

  2. Improved User Experience

    • Single Sign-On capabilities

    • Streamlined authentication flows

  3. Operational Benefits

    • Centralized identity management

    • Reduced operational overhead

Core Components of OIDC

Identity Provider (IdP)

Think of the IdP as the trusted security guard of your system. Common examples include:

  • GitHub

  • Auth0

  • Google

  • Microsoft Azure AD

ID Token Structure

The ID Token is a JWT (JSON Web Token) containing vital information:

{
  "iss": "https://token.actions.githubusercontent.com",
  "sub": "repo:organization/repository:ref:refs/heads/main",
  "aud": "https://github.com/organization",
  "exp": 1584979794,
  "iat": 1584979494
}

Claims Explained

  • iss (Issuer): The token creator

  • sub (Subject): The token's intended user

  • aud (Audience): The token's intended recipient

  • exp (Expiration): Token expiry timestamp

  • iat (Issued At): Token creation time

Relying Party (RP)

The application seeking to authenticate users. It:

  • Validates tokens (ID Tokens)

  • Processes claims

  • Manages user sessions

  • Integrates with protected resources

Claims

Identity information embedded into the ID Token, including:

  • aud (audience): Intended recipient of the token

  • iss (issuer): Entity that issued the token

  • exp (expiration): Token expiration timestamp

  • sub (subject): Subject identifier

  • Additional custom claims as needed

Issuer

The identifier of the OpenID Provider. This is usually a URL included in tokens to verify their origin.

Access Token

Credentials issued alongside ID Token to the Relying Party, used to:

  • Access protected resources

  • Make authenticated API calls

  • Represent granted permissions

Authorization Code

A temporary code obtained during the authorization process. The Relying Party exchanges this code for an ID Token and an Access Token.

OIDC Authentication Flow Steps

Overview

The OIDC authentication flow involves interactions between three parties:

  • User

  • Application (Relying Party)

  • Identity Provider (IdP)

Each step in the flow serves a specific purpose in establishing secure authentication.

Flow Sequence

1. Initial Access Request

User → Application (Relying Party)

  • User attempts to access protected resource

  • Example: Clicking "Login with GitHub" button

  • Application checks for valid session

2. Authorization Request

Application → Identity Provider

GET /authorize
Host: identity-provider.com
Parameters:
  response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://url.com/callback
  &scope=openid profile email
  &nonce=another_random_string

Required Parameters:

ParameterDescription
response_typeMust be 'code' for authorization code flow
client_idYour application's identifier
redirect_uriURL where IdP will send the response
scopeRequested permissions (must include 'openid')
nonceRandom string to prevent replay attacks

3. Authentication Prompt

Identity Provider → User

  • Displays login interface

  • Handles SSO if applicable

  • Manages 2FA if configured

  • Shows consent screen for requested permissions

4. Credential Submission

User → Identity Provider

  • User provides authentication credentials

  • Could be username/password

  • May include 2FA verification

  • User grants consent for requested scopes

5. Authorization Code Response

Identity Provider → Application

HTTP/1.1 302 Found
Location: https://url.com/callback?
  code=AUTHORIZATION_CODE
  &state=random_secure_string

6. Token Exchange

Application → Identity Provider

POST /token HTTP/1.1
Host: identity-provider.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=AUTHORIZATION_CODE
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&redirect_uri=https://url.com/callback

7. Token Response

Identity Provider → Application

{
  "id_token": "eyJ0eXAi...",
  "access_token": "eij_16C7e42F292c6912E7710...",
  "token_type": "Bearer",
  "expires_in": 3600
}

OIDC Authentication Flow in Practice - GitHub Actions & AWS

In our deployment scenario, let's map the OIDC components to actual services:

  • Identity Provider (IdP): GitHub - provides identity verification

  • Relying Party (RP): AWS - consumes and trusts GitHub's identity verification

  • User: Your GitHub Actions workflow - the entity requesting access

Flow Breakdown with GitHub Actions and AWS

  1. Initial Request

    • Your GitHub Actions workflow (User) needs to deploy to AWS

    • AWS (RP) requires authentication

    • Instead of static credentials, we use OIDC

  2. Authorization Request

    • GitHub Actions workflow requests authentication from GitHub (IdP)

    • The request includes the workflow's identity information like:

        {
          "repository": "org/repo",
          "workflow": "deploy.yml",
          "ref": "refs/heads/main"
        }
      
  3. Token Generation

    • GitHub (IdP) generates a JWT token containing claims like:

        {
          "iss": "https://token.actions.githubusercontent.com",
          "sub": "repo:myorg/myrepo:ref:refs/heads/main",
          "aud": "sts.amazonaws.com",
          "exp": 1584979794
        }
      
  4. Token Verification

    • AWS (RP) receives the token

    • Validates it came from GitHub (IdP)

    • Checks the claims match the trust policy:

        {
          "Condition": {
            "StringLike": {
              "token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:*"
            }
          }
        }
      
  5. Access Granted

    • AWS provides temporary credentials

    • GitHub Actions workflow can now access AWS resources

    • Credentials automatically expire after the workflow completes

Implementing OIDC with GitHub Actions and AWS

Now, let's look at a practical implementation using GitHub Actions and AWS.

Setting Up AWS OIDC Provider

aws iam create-open-id-connect-provider \
  --url https://token.actions.githubusercontent.com \
  --client-id-list "sts.amazonaws.com" \
  --thumbprint-list "6938fd4d98bab03faadb97b34396831e3780aea1"

Creating the IAM Role

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::ACCOUNT-ID:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:organization/repository:*"
        },
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        }
      }
    }
  ]
}

Configuring GitHub Actions

name: Application Deployment

on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          role-to-assume: arn:aws:iam::ACCOUNT-ID:role/ROLE-NAME
          aws-region: eu-central-1

      - name: Deploy some workload to aws
        run: |
          aws ...

Security Best Practices

1. Access Control

  • Apply least privilege principle

  • Use conditional access

  • Implement role-based access

  • Regular access reviews

Extras

Conditional Access

Control access based on:

  • Repository name

  • Branch name

  • Environment

  • Actor (user/service)

Example condition:

"Condition": {
  "StringEquals": {
    "token.actions.githubusercontent.com:sub": [
      "repo:org/repo:ref:refs/heads/main",
      "repo:org/repo:environment:production"
    ]
  }
}

Resources and Next Steps

Official Documentation

Tools and Libraries

Conclusion

OIDC integration between GitHub Actions and AWS eliminates the need to store AWS credentials as GitHub secrets. Instead, it establishes a trust relationship that generates short-lived tokens during workflow execution, significantly reducing the attack surface of your CI/CD pipeline

10
Subscribe to my newsletter

Read articles from Oluwatunmise Olatunbosun directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Oluwatunmise Olatunbosun
Oluwatunmise Olatunbosun

Results-driven Software Engineer specializing in cloud-native architectures and scalable systems. Experienced in building resilient systems, automating cloud infrastructure, and implementing reliability patterns that drive measurable business impact.