Fix AWS CLI Error 'InvalidClientTokenId': The Security Token Included in the Request is Invalid

beginnerโ˜๏ธ AWS2026-03-24| AWS CLI v2 on Linux, macOS, Windows โ€” any region, any IAM user or role

Error Message

An error occurred (InvalidClientTokenId) when calling the GetCallerIdentity operation: The security token included in the request is invalid.
#aws#cli#iam#access-key#credentials

The Scenario

It's late. A deploy just failed. You run a quick aws s3 ls to check something and instead of a bucket list, you get this:

An error occurred (InvalidClientTokenId) when calling the GetCallerIdentity operation: The security token included in the request is invalid.

Nothing in the code changed. The pipeline worked yesterday. Now AWS won't even acknowledge who you are.

This error means AWS rejected your credentials before evaluating any permission policy. It never got that far โ€” the access key itself is invalid, deleted, or never matched a real IAM user.

What's Actually Going On

InvalidClientTokenId is not an "access denied" error. It's earlier than that. AWS couldn't find an IAM entity matching the Access Key ID you sent. The most common causes:

  • The access key was deleted or deactivated in IAM
  • The key belongs to a different AWS account than the one you're targeting
  • Wrong region set โ€” some services (especially STS) need an explicit region
  • The credentials file has a stale key that was rotated elsewhere
  • Environment variable AWS_ACCESS_KEY_ID is silently overriding your profile
  • The key was generated for an IAM user that was later deleted
  • Copy-paste introduced hidden characters into the key string

Quick Diagnosis

Before touching anything, find out which credentials the CLI is actually using:

# See exactly which key ID is being sent
aws configure list

# Output looks like:
#      Name                    Value             Type    Location
#      ----                    -----             ----    --------
#   profile                <not set>             None    None
#access_key     ****************ABCD shared-credentials-file
#secret_key     ****************wxyz shared-credentials-file
#    region                us-east-1      config-file    ~/.aws/config

Note the last 4 characters of the Access Key ID shown. Cross-check that against IAM in the AWS Console โ€” go to IAM โ†’ Users โ†’ your user โ†’ Security credentials. If that key isn't listed as active, that's your culprit right there.

Next, check whether an environment variable is overriding your profile:

# Linux / macOS
echo $AWS_ACCESS_KEY_ID
echo $AWS_SECRET_ACCESS_KEY
echo $AWS_PROFILE

# Windows (PowerShell)
$env:AWS_ACCESS_KEY_ID
$env:AWS_SECRET_ACCESS_KEY

Old values in those variables silently override everything in ~/.aws/credentials. No warning, no indication โ€” they just take precedence.

Fix 1 โ€” Clear Stale Environment Variables

Env vars the problem? Unset them and retry:

# Linux / macOS
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN

# Windows (PowerShell)
Remove-Item Env:AWS_ACCESS_KEY_ID -ErrorAction SilentlyContinue
Remove-Item Env:AWS_SECRET_ACCESS_KEY -ErrorAction SilentlyContinue
Remove-Item Env:AWS_SESSION_TOKEN -ErrorAction SilentlyContinue

Then verify:

aws sts get-caller-identity

Fix 2 โ€” Reconfigure with a Valid Key

When the key itself is stale or deleted, generate a fresh one:

  • Log into the AWS Console โ†’ IAM โ†’ Users โ†’ your user โ†’ Security credentials
  • If the old key is listed, deactivate it first, then delete it
  • Click Create access key โ†’ select "CLI" use case
  • Copy both the Access Key ID and Secret Access Key immediately โ€” the secret is shown exactly once

Now configure the CLI:

aws configure
# AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
# AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# Default region name [None]: ap-southeast-1
# Default output format [None]: json

Or update just the credentials without touching region or output format:

aws configure set aws_access_key_id AKIAIOSFODNN7EXAMPLE
aws configure set aws_secret_access_key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

Fix 3 โ€” Edit the Credentials File Directly

Faster when managing multiple profiles. Open the file and inspect it:

# Linux / macOS
cat ~/.aws/credentials

# Windows
type %USERPROFILE%\.aws\credentials

A healthy file looks like this:

[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

[staging]
aws_access_key_id = AKIAI44QH8DHBEXAMPLE
aws_secret_access_key = je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY

Watch for hidden characters around the key values. This happens after copying from Slack, Confluence, or a PDF. Long-term keys always start with AKIA; temporary STS keys start with ASIA. Anything else prepended or appended is the bug.

Fix 4 โ€” STS Temporary Credentials Expired

Keys starting with ASIA are temporary โ€” issued by aws sts assume-role or SSO. They expire after 1 hour by default, up to 12 hours if configured. Refresh them:

# Check if there's a session token in your credentials
grep session_token ~/.aws/credentials

# If using SSO, re-login
aws sso login --profile your-profile

# If using assume-role, re-assume
aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/YourRole \
  --role-session-name session1 \
  --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
  --output text

Verify the Fix

# This should return your account ID, user ARN, and user ID
aws sts get-caller-identity

# Expected output:
# {
#     "UserId": "AIDIODR4TAW7CSEXAMPLE",
#     "Account": "123456789012",
#     "Arn": "arn:aws:iam::123456789012:user/your-username"
# }

Clean output means you're done. Still seeing InvalidClientTokenId? The key in the credentials file still doesn't match any active IAM user. Double-check you saved the correct key โ€” and confirm the IAM user itself hasn't been deleted from the account.

Prevention

Most InvalidClientTokenId incidents trace back to the same thing: key rotation in IAM, but no one updated CI/CD, the local machine, or the deployed service. The key and the record of it drift apart.

  • Use IAM roles instead of long-term keys wherever possible โ€” EC2 instance profiles, Lambda execution roles, ECS task roles. These rotate automatically and never expire.
  • Rotate long-term keys every 90 days. IAM Access Analyzer can flag keys older than your policy threshold.
  • Store keys in a secrets manager โ€” AWS Secrets Manager, 1Password, or similar. Plaintext files have no audit trail and no central update point.
  • When testing credential workflows, use a tool like the Password Generator at ToolCraft to generate strong random strings. Runs entirely in the browser, nothing uploaded.
  • Audit active keys with: aws iam list-access-keys --user-name your-user

Multiple Profiles Getting Confused?

Juggling multiple AWS accounts? Be explicit about which profile you're targeting:

# Temporarily use a specific profile
AWS_PROFILE=staging aws sts get-caller-identity

# Or pass it as a flag
aws --profile staging s3 ls

# Set a default for the current shell session
export AWS_PROFILE=staging

This sidesteps the classic mistake of running a command against prod while thinking you're on staging. It also surfaces key mismatches immediately โ€” per environment, not after the damage is done.

Related Error Notes