Securing your GitHub Workflows with OIDC: Connection to AWS explained

We’ve all seen it: AWS keys sitting in GitHub Workflows. They might feel convenient at first, but if they ever leak, it’s a nightmare—especially when those keys have wide IAM permissions.
Rotating them every 90 days means generating new keys, updating environments, and hoping nothing breaks in the process.
And really, why keep replacing long-term credentials every 90 days? That’s just turning long-term creds into short-term ones the hard way. Why not start with short-term credentials from the beginning and avoid the problem altogether?
How does OIDC work?
That's where the OpenID Connect (OIDC) protocol comes in. Through a series of verifications between GitHub and AWS, it provides short-term credentials instantly to run the GitHub workflow and use resources from AWS.
This protocol has three main actors
Github workflow
GitHub as an Identity provider
AWS STS as Authorizer and credentials issuer
Let’s have a general picture of how the communication flows between these actors:
GitHub, acting as an identity provider, issues a token when the GitHub workflow begins.
A GitHub Action aws-actions/configure-aws-credentials sends this OIDC token to AWS STS via the API call
AssumeRoleWithWebIdentity, along with the IAM Role Arn and optional configurations like the TTL.STS validates the token against the OIDC identity provider you configured in AWS IAM, comparing its properties against the trust policy configured on the IAM Role, and returns short-term credentials in case of success.
The workflow now uses those short-term credentials to run AWS CLI commands, Terraform, CDK, etc, using the same permissions as the IAM role has defined
Here is a Sequence-System Diagram of the above flow:

What is AWS STS?
AWS STS (Security Token Service) is an AWS service that allows you to request temporary security credentials for AWS resources instead of using long-term IAM user access keys.
These temporary credentials are:
Short-lived (from a few minutes up to a maximum of 12 hours, depending on the request).
Scoped to specific permissions (defined by IAM roles and policies).
Automatically expire, reducing the risk if they get exposed.
It’s the key player on the OIDC implementation with AWS.
Key uses of AWS STS:
AssumeRole – Allows one AWS service, user, or external identity (like GitHub via OIDC) to temporarily act as another role with specific permissions.
Federation – Provides temporary credentials for external users authenticated by identity providers (like Google, Active Directory, GitHub).
Cross-account access – Lets you securely access resources in another AWS account without creating permanent users.
IAM role session management – Useful for apps, CI/CD pipelines, or temporary jobs that only need short-lived access.
Contrary to what you might think, this OIDC process falls under the second use case: Federation. This is because, initially, you don't have any AWS credentials. AWS federates an external identity into AWS to generate short-lived credentials. In other scenarios, you begin with AWS credentials and request temporary credentials to assume a role or start a new session for security reasons.
How does the AWS STS validation process works?
Here is a flowchart that describes in detail the validation process AWS STS performs to issue short-term credentials. This provides a deeper look into points 2 and 3 from the previous picture showing the general communication flow.
![flowchart TD A["Start: STS receives AssumeRoleWithWebIdentity request with OIDC token + RoleArn"] --> B["Check: Does IAM account have an OIDC provider for this issuer?"] B -->|No| Z["Reject: InvalidIdentityToken"] B -->|Yes| C["Verify TLS certificate or thumbprint of OIDC provider endpoint"] C -->|Invalid| Z C -->|Valid| D["Fetch JWKS from provider and verify JWT signature"] D -->|Invalid signature| Z D -->|Valid signature| E["Validate JWT standard claims: iss, aud, exp, nbf, iat"] E -->|Expired / invalid| Z["Reject: ExpiredToken or InvalidIdentityToken"] E -->|Valid| F["Evaluate IAM role trust policy conditions against token claims (sub, repository, ref, aud, etc.)"] F -->|Claims don't match| Z["Reject: IDPRejectedClaim"] F -->|Claims match| G["Issue temporary STS credentials (AccessKeyId, SecretAccessKey, SessionToken, Expiration)"] G --> H["Return credentials to caller"] H --> I["Caller uses temporary credentials for AWS API calls until expiration"] I --> J["End"]](https://cdn.hashnode.com/res/hashnode/image/upload/v1760973918728/87bc275b-2f88-431f-8820-d40717f16aa2.png)
In simple terms, the validation process goes like this:
AWS checks whether it has configured GitHub as an identity provider.
It then verifies the authenticity of the OIDC token by checking if it was issued by GitHub and confirming its TLS certificate or thumbprint.
It verifies the token signature.
It compares the token payload claims against the properties set in the IAM Role trust policy, such as repository, branch, environment, sub, etc.
If everything is correct, AWS STS issues temporary credentials that are returned to the caller.
Conclusion
OpenID Connect (OIDC) lets your GitHub Actions talk to AWS in a secure, short-lived, and trust-based way. No need to deal with long-term access keys ever again.
With OIDC, you can ditch static credentials, skip the rotation headaches, and set up fine-grained permissions that map directly to your repo and branches. It’s cleaner, safer, and follows AWS’s best practices for least privilege and temporary credentials.
So really, what are you waiting for to switch to OIDC?
Next steps
In the next article, I’ll walk you through how to set up OIDC between AWS and GitHub step by step, so you can securely assume roles without adding extra complexity.



