How to Fix AWS Authentication Errors (InvalidClientTokenId, ExpiredTokenException, SignatureDoesNotMatch)
This page covers AWS CLI, SDK, and API authentication failures: InvalidClientTokenId, SignatureDoesNotMatch, ExpiredTokenException, and IAM Identity Center SSO session expiry. These errors happen before AWS checks your permissions. You do not need to change IAM policies to fix them.
Quick fix checklist
START HERE
Run aws sts get-caller-identity before anything else. If it succeeds, your authentication is fine and you have an authorization problem instead. See IAM AccessDenied Errors.
Work through this sequence in order:
-
Run the identity check:
aws sts get-caller-identity -
Check for stale environment variables. These override everything else, including
--profileflags:echo $AWS_ACCESS_KEY_ID echo $AWS_PROFILE # Clear them if they are wrong: unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN -
Check whether you need a session token. Access key IDs starting with
ASIAare temporary. Setting only the key ID and secret key is not enough. You must also exportAWS_SESSION_TOKEN. -
Refresh your SSO session if you use IAM Identity Center:
aws sso login --profile your-sso-profile -
Check your system clock if you see
SignatureDoesNotMatchwith keys that look correct. AWS rejects requests with a timestamp more than 15 minutes off. -
Re-assume the role if you see
ExpiredTokenExceptionin a CI/CD job or long-running script.
Simple explanation
When you run an AWS CLI command, AWS answers two questions in sequence:
- Who are you? (authentication)
- Are you allowed to do this? (authorization)
Authentication errors happen at step 1. AWS is not saying you lack permission. It is saying it cannot verify your identity at all.
Think of it like online banking. To log in, you enter a username, a password, and sometimes a one-time code your bank texts you. The username identifies your account. The password proves you own it. The one-time code proves the session was freshly started and has not expired. AWS credentials work the same way. For permanent keys (starting with AKIA), you only need the username and password. For temporary keys (starting with ASIA), you also need the one-time code — that is the session token. Send two out of three and the login fails.
Here is how the three credential types map to that analogy:
| Credential type | Access key starts with | Requires session token? | How long it lasts |
|---|---|---|---|
| IAM user long-term key | AKIA | No | Until rotated or deleted |
| STS temporary credential | ASIA | Yes | Minutes to hours (set at issue time) |
| IAM Identity Center / SSO | ASIA | Yes | Duration set in SSO configuration |
If any required piece is wrong, missing, or expired, AWS returns an authentication error.
For a deeper look at how access keys and temporary credentials differ, see Access Keys Explained and STS Temporary Credentials.
How AWS authentication works for CLI and SDK requests
The AWS CLI and all AWS SDKs use a credential provider chain: a prioritised list of places to look for credentials. The first source that returns a complete credential set wins.
The standard order is:
- Environment variables:
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_SESSION_TOKEN AWS_PROFILEenvironment variable: points to a named profile in~/.aws/credentialsor~/.aws/config- Default profile: the
[default]section in~/.aws/credentials/~/.aws/config - AWS SSO / IAM Identity Center: if the active profile is configured for SSO
- ECS container credentials:
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI(set automatically for ECS task roles) - EC2 instance metadata:
http://169.254.169.254/...(set automatically for EC2 instance profiles and Lambda execution roles)
ENVIRONMENT VARIABLES ALWAYS WIN
Environment variables are checked first, so they override everything — including explicit —profile flags. A AWS_ACCESS_KEY_ID set from an earlier test or injected by a CI/CD system will be used even if you pass —profile prod. If you suspect the wrong credentials are active, run aws configure list to see which source is winning.
Why ASIA credentials without a session token always fail: Temporary credentials are not just a key pair. An ASIA access key ID without its session token is meaningless to AWS. All three parts must come from the same AssumeRole or GetSessionToken response.
Why sessions expire: When you call sts:AssumeRole or log into IAM Identity Center, AWS issues a credential set with an embedded expiry timestamp. AWS checks that timestamp on every request. Once it passes, every call returns ExpiredTokenException. There is no extension — you re-assume the role to get a fresh set.
For how roles and trust policies control who can assume what, see Role Assumption in AWS and IAM Roles Explained.
Error quick-reference table
| Error | What it usually means | First thing to check | Typical fix |
|---|---|---|---|
InvalidClientTokenId | Access key ID not recognised | Is it an ASIA key missing a session token? Was the key deleted? | Add AWS_SESSION_TOKEN; re-create the access key |
SignatureDoesNotMatch | Secret key wrong, or clock is off | Is the secret key pasted correctly, no whitespace? Is system clock synced? | Re-paste the secret key; sync clock with NTP |
ExpiredTokenException | STS temporary credential has passed its expiry | How long ago were these credentials issued? | Re-assume the role for fresh credentials |
TokenRefreshRequired | IAM Identity Center SSO session expired | When did you last run aws sso login? | aws sso login --profile <name> |
AccessDenied: token has expired | Same as ExpiredTokenException (some services surface it differently) | Same as above | Same as above |
InvalidSignatureException | Signature calculation failed | Clock skew or wrong region endpoint | Sync clock; verify region configuration |
Troubleshooting specific AWS authentication errors
InvalidClientTokenId
An error occurred (InvalidClientTokenId) when calling the GetCallerIdentity operation:
The security token included in the request is invalid.What it means: The access key ID is not recognised by AWS. This is not a permissions problem. AWS cannot match the key ID to any valid credential set at all.
Most likely causes:
- You are using an
ASIAtemporary key without providingAWS_SESSION_TOKEN - The access key was deleted from IAM (or the IAM user was deleted)
- The key ID is mistyped, truncated, or has extra whitespace
- The key belongs to a different AWS account than the endpoint you are calling
How to diagnose:
# Confirm what key ID is actually being used
aws sts get-caller-identity 2>&1
# Check what is in your environment
echo "Key ID: $AWS_ACCESS_KEY_ID"
echo "Session token set: $([ -n "$AWS_SESSION_TOKEN" ] && echo yes || echo no)"
# Check how the active profile is configured
aws configure listASIA KEYS NEED ALL THREE VARIABLES
If your access key ID starts with ASIA, you must export all three variables together from the same credential response: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN. Setting only two will always fail. This is the single most common cause of InvalidClientTokenId.
Fixes:
- If the key starts with
ASIA: export all three variables from the sameAssumeRoleresponse - If the key starts with
AKIAand is not recognised: re-create the access key in IAM and reconfigure withaws configure - Unset stale environment variables that may be shadowing a working profile
SignatureDoesNotMatch
An error occurred (SignatureDoesNotMatch) when calling the GetCallerIdentity operation:
The request signature we calculated does not match the signature you provided.What it means: The key ID is recognised, but the secret access key does not match it, or the request timestamp is too far from AWS server time.
Most likely causes:
- Wrong secret access key: extra whitespace on paste, truncated, or a line break included
- Access key ID and secret access key swapped (the ID is
AKIA..., not the secret) - System clock more than 15 minutes off from UTC
How to diagnose:
# Compare your system time against AWS server time
date -u
curl -sI https://aws.amazon.com 2>/dev/null | grep -i "^date:"
# Verify both fields are filled in for the active profile
aws configure list --profile your-profile-nameFixes:
- Re-paste the secret access key carefully: select the full value with no surrounding whitespace
- Confirm you have not swapped key ID and secret
- Sync your system clock:
# Linux (systemd)
sudo timedatectl set-ntp true
# Linux (ntpd)
sudo ntpdate pool.ntp.org
# macOS
sudo sntp -sS time.apple.comCONTAINERS AND VMs DRIFT FASTER
Clock skew is more common in containers and virtual machines because the guest clock can fall behind the host clock over time. If you see SignatureDoesNotMatch only in containerised jobs, confirm that NTP is running on the host, not just inside the container.
ExpiredTokenException
An error occurred (ExpiredTokenException) when calling the DescribeInstances operation:
The security token included in the request is expired.What it means: Temporary credentials from STS have passed their expiry time. Every API call will return this error until you get a fresh credential set.
Most likely causes:
- AssumeRole credentials used beyond their session duration (default: 1 hour)
- A script that exports STS output at job start and then runs longer than the credential duration
- Credentials exported as environment variables hours or days ago and left set
How to check the expiry time:
aws sts assume-role \
--role-arn arn:aws:iam::111122223333:role/my-role \
--role-session-name debug \
--query 'Credentials.Expiration'Fix — re-assume the role and export fresh credentials:
CREDS=$(aws sts assume-role \
--role-arn arn:aws:iam::111122223333:role/my-role \
--role-session-name my-session \
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
--output text)
export AWS_ACCESS_KEY_ID=$(echo $CREDS | awk '{print $1}')
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | awk '{print $2}')
export AWS_SESSION_TOKEN=$(echo $CREDS | awk '{print $3}')For automation, the better fix is to stop holding credentials at all. See CI/CD and automation failure patterns below.
TokenRefreshRequired / token has expired
Error when retrieving credentials from sso: Token has expired and refresh failedor:
An error occurred (TokenRefreshRequired) when calling the GetObject operation:
The provided token has expired.What it means: An IAM Identity Center (SSO) session has expired. SSO sessions are browser-authenticated with a configurable duration, typically 8 hours. When the session ends, every profile that relied on that login stops working.
Fix:
# Log in again (opens a browser)
aws sso login --profile your-sso-profile
# Verify it worked
aws sts get-caller-identity --profile your-sso-profileTo check when the current SSO session expires:
cat ~/.aws/sso/cache/*.json | python3 -c "
import json, sys
for line in sys.stdin:
try:
data = json.loads(line)
if 'expiresAt' in data:
print('Expires at:', data['expiresAt'])
except:
pass
"SSO IS FOR HUMANS, NOT PIPELINES
SSO sessions require a browser to refresh. Automated CI/CD pipelines cannot re-authenticate this way. Use GitHub Actions OIDC, ECS task roles, EC2 instance profiles, or another secure CI/CD credentials approach for anything that runs without a human present.
MFA-required authentication and session issues
Some IAM policies use a condition that requires MFA for sensitive operations:
{
"Effect": "Deny",
"Action": ["iam:DeleteUser", "iam:DeleteRole"],
"Resource": "*",
"Condition": {
"BoolIfExists": {"aws:MultiFactorAuthPresent": "false"}
}
}When a user without an active MFA session tries this action, they get AccessDenied with a message indicating MFA is required. The fix is to get a session token that carries MFA proof:
aws sts get-session-token \
--serial-number arn:aws:iam::111122223333:mfa/alice \
--token-code 123456 \
--duration-seconds 3600
# Export the returned credentials
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_SESSION_TOKEN="..."Then retry the operation. The session token embeds proof that MFA was present when it was issued.
When to use this page
This page is for you if:
- AWS CLI commands that were working suddenly return
InvalidClientTokenId,SignatureDoesNotMatch, orExpiredTokenException - A CI/CD job fails with an authentication error partway through, especially if it starts fine and breaks hours later
- Your IAM Identity Center SSO session expired and commands are returning token errors
- You have multiple AWS accounts and suspect the wrong profile or account is active
- You copied temporary credentials into environment variables and they have stopped working
- You see
SignatureDoesNotMatchand cannot figure out why when the keys look correct
This page is not for:
AccessDeniederrors whereaws sts get-caller-identitysucceeds: that is an authorization problem. See IAM AccessDenied Errors- AWS Console browser login failures (password or MFA device issues)
- VPC or network connectivity problems: see Debugging VPC Connectivity
Authentication errors vs AccessDenied errors in AWS
These two failure types look similar in the terminal but have completely different causes and fixes.
| Authentication error | Authorization error | |
|---|---|---|
| Examples | InvalidClientTokenId, SignatureDoesNotMatch, ExpiredTokenException | AccessDenied, UnauthorizedOperation |
| What it means | AWS cannot verify who you are | AWS knows who you are but will not allow the action |
Does aws sts get-caller-identity succeed? | No | Yes |
| Fix involves | Credentials: refresh, re-paste, or re-assume | IAM policies: add or correct permissions |
| Change IAM policy to fix? | No | Usually yes |
THE ONE-COMMAND TEST
Run aws sts get-caller-identity. If it fails, you have an authentication problem and this page is for you. If it succeeds, authentication is working and you have an authorization problem. Read IAM AccessDenied Errors or Permission Denied Errors instead.
The distinction matters because fixing authentication never involves IAM policies, and fixing authorization never involves credential rotation. Treating one as the other wastes time.
For auditing both types of failure in logs, see CloudTrail Overview.
CI/CD and automation failure patterns
Authentication errors in CI/CD almost always share the same root cause: a job that assumes a role once at start and holds those credentials longer than their session duration.
The classic scenario:
A deploy pipeline runs at midnight. It calls sts:AssumeRole at job start and exports the credentials. Deployment finishes in 20 minutes. A post-deployment health check runs at 4am — using credentials that expired at 1am. Every call returns ExpiredTokenException.
# The AssumeRole that caused the problem
aws sts assume-role \
--role-arn arn:aws:iam::111122223333:role/deploy-role \
--role-session-name deploy \
--query 'Credentials.Expiration'
# Returns: "2026-03-19T01:00:00Z" — expired 3 hours before the health check ranTemporary fix: Have each stage that needs AWS access assume the role independently so each step gets its own fresh credentials.
Proper fix: Use a credential source that does not require manual rotation:
| Environment | Recommended credential source |
|---|---|
| GitHub Actions | OIDC via aws-actions/configure-aws-credentials — no static keys needed |
| GitLab CI | OIDC / JWT-based role assumption |
| EC2 | Instance profile: automatic, rotated by AWS |
| ECS | Task role: defined per task definition |
| Lambda | Execution role: automatic, no credentials to manage |
| EKS | IAM Roles for Service Accounts (IRSA) |
LONG-LIVED ACCESS KEYS IN CI/CD ARE A LEGACY PATTERN
Long-lived access keys in automated pipelines require manual rotation, are easy to leak, and create exactly the credential management failures described on this page. Use OIDC, instance profiles, or task roles instead. If you are currently using static keys in CI/CD, read Why Long-Lived Access Keys Are Dangerous for the full picture.
Common mistakes
- Using
ASIAtemporary credentials withoutAWS_SESSION_TOKEN— temporary credentials are a three-part set. Setting only the key ID and secret for anASIAkey always givesInvalidClientTokenId. All three variables must be exported together from the same credential response. - Leaving
AWS_ACCESS_KEY_IDset in the environment and forgetting about it — environment variables override profile credentials. A shell session with stale exports will use those credentials even after you switch profiles or accounts, because environment variables are always checked first. - Swapping the access key ID and secret access key — the access key ID starts with
AKIAorASIAand is not the secret. The secret access key is a long random string. Putting them in the wrong fields causesSignatureDoesNotMatch. - Holding temporary credentials across a long-running CI/CD job — STS credentials issued at job start expire while the job is still running. Each stage that needs AWS access should either re-assume the role or use a managed credential provider that auto-rotates.
- Using SSO sessions in automated systems — SSO sessions require interactive browser re-authentication. Automated CI/CD pipelines cannot do this. Use OIDC, instance profiles, or task roles instead. See GitHub Actions for AWS for a practical OIDC setup.
Summary
- Run
aws sts get-caller-identityfirst. If it succeeds, authentication is working and you have an authorization problem, not a credentials problem. - Authentication errors (InvalidClientTokenId, SignatureDoesNotMatch, ExpiredTokenException) are about identity verification, not IAM permissions. You do not fix them by changing policies.
- The SDK credential chain checks environment variables first. Stale exports override everything else, including explicit
—profileflags. ASIAtemporary credentials require all three pieces: access key ID, secret key, and session token. Missing the session token always givesInvalidClientTokenId.- STS temporary credentials expire. CI/CD automation should use managed credential sources (OIDC, instance profiles, task roles) that rotate automatically rather than holding static keys.
Frequently asked questions
What is the difference between authentication and authorization in AWS?
Authentication is AWS verifying your identity — your credentials are valid and recognisable. Authorization is AWS checking whether that identity has permission to do the thing. Authentication errors (InvalidClientTokenId, SignatureDoesNotMatch, ExpiredTokenException) happen before authorization even starts. Authorization errors appear as AccessDenied. If you can run aws sts get-caller-identity successfully, your authentication is working.
Why does AWS say my security token is invalid?
The most common reason is that you are using a temporary credential set (access key ID starting with ASIA) but have not set the AWS_SESSION_TOKEN environment variable. Temporary credentials are a three-part set — access key ID, secret key, and session token — and all three must be present. A missing or stale session token gives InvalidClientTokenId.
Why do temporary AWS credentials stop working?
Temporary credentials from STS (AssumeRole, GetSessionToken, or SSO) expire after a fixed duration. AssumeRole defaults to 1 hour (maximum 12 hours). AWS SSO sessions typically last 8 hours. There is no way to extend them — you must re-assume the role or re-authenticate to get a fresh set. Automated systems should use a managed credential source (EC2 instance profile, ECS task role, Lambda execution role, EKS IRSA) that rotates credentials automatically.
Why does SignatureDoesNotMatch happen even when my keys look correct?
The most likely cause is a wrong secret access key — perhaps copied with extra whitespace, truncated, or pasted from the access key ID field by mistake. The second most common cause is clock skew: AWS rejects requests where the timestamp differs from server time by more than 15 minutes. Check your system clock, and confirm you have the secret key (the long random string), not the access key ID (which starts with AKIA or ASIA).
How do I check which AWS identity my CLI is using?
Run: aws sts get-caller-identity. This returns the account ID, ARN, and user or role that your current credentials represent. It works regardless of which credential source is active — environment variables, profile, SSO, or instance profile. Run it first whenever authentication fails.