| Package | aws-cli/2.37.3 |
|---|---|
| AWS Region | ap-south-1 (Mumbai) for the examples. IAM is global; AWS STS supports global and Regional endpoints, and AWS recommends Regional STS endpoints. |
| Lab environment | Workstation with AWS CLI v2 and configured credentials — AWS CLI tutorial Install AWS CLI on Ubuntu · Install AWS CLI on Debian |
| Privilege | Access required by the credential source being refreshed. GetSessionToken itself does not require an IAM permission; AssumeRole requires the target role to trust the caller and any required caller-side permission to assume that role; IAM Identity Center and aws login require their respective sign-in access. |
| Scope | Why AWS returns ExpiredToken when temporary STS credentials are past their expiration time, how to read aws configure list to see whether environment variables, a named profile, AssumeRole cache, or login/SSO session supplied the keys, and how to refresh each source. Does not cover rejected or unknown credentials (InvalidClientTokenId) or missing credentials (Unable to locate credentials). |
| Related guides | AWS CLI Tutorial Fix AWS CLI InvalidClientTokenId Fix Terraform AWS ExpiredToken Fix AWS CLI Unable to locate credentials AWS Tutorial |
ExpiredToken means the AWS CLI is using temporary credentials that have passed their expiration time. The credentials may have come from STS, an assumed role, IAM Identity Center, aws login, or exported environment variables. The fix is to refresh the source that created those credentials, not to change IAM permissions.
Start with aws configure list to find which credential provider the failing shell is actually using. The walkthrough uses isolated credential files and short-lived sts get-session-token sessions so each failure mode is visible without touching production profiles. Editing duration_seconds in a profile or rotating a long-term access key does not extend a session that was already issued.
What ExpiredToken means
ExpiredToken is an authentication failure on temporary credentials. AWS accepted the request format but the session token is past its expiration time. HTTP status is 403 Forbidden, and the error code is not AccessDenied.
Common message:
An error occurred (ExpiredToken) when calling the GetCallerIdentity operation: The security token included in the request is expiredThat differs from InvalidClientTokenId, where the credential bundle is rejected as invalid, and from Unable to locate credentials, where the CLI never resolved signing material. See Fix AWS CLI InvalidClientTokenId when the error names an invalid token rather than an expired one.
| Error code | Meaning | Typical next step |
|---|---|---|
ExpiredToken |
Temporary session past expiration | Refresh SSO, login, role, or exported session credentials |
InvalidClientTokenId |
Credential or token rejected as invalid | Run aws configure list; fix stale keys or incomplete triplets |
SignatureDoesNotMatch (with clock wording) |
Signature or clock skew | Sync NTP; then refresh credentials if needed |
AccessDenied |
Identity authenticated; action denied | Read IAM policies — not an ExpiredToken case |
Unable to locate credentials |
No credential chain | Configure a profile or export keys |
Temporary access key IDs use the ASIA prefix. They are valid only with the matching secret key and session token until the expiration timestamp AWS returned when the session was created.
ExpiredToken
↓
aws configure list
↓
┌──────────┬──────────┬──────────┬──────────┐
│ │ │ │ │
env ASIA? role prof SSO/login EC2 role?
│ │ │ │
↓ ↓ ↓ ↓
unset + refresh aws sso unset stale
re-export source login or env; let
profile aws login IMDS refresh
│ │ │ │
└──────────┴──────────┴──────────┴──────────┘
↓
aws sts get-caller-identityIncreasing duration_seconds changes the requested length of future AssumeRole sessions. It does not extend an AssumeRole credential set that has already been issued or exported. IAM Identity Center and aws login session lifetimes are managed separately by those authentication mechanisms.
Find which temporary credentials are active
Run aws configure list in the same shell where the failing command runs. The TYPE and LOCATION columns show whether environment variables, a profile, or assume-role resolution supplied the keys.
aws configure listWhen temporary keys come from the environment, LOCATION shows env for the access key row:
NAME : VALUE : TYPE : LOCATION
profile : <not set> : None : None
access_key : ****************3VHR : env :
secret_key : ****************xs48 : env :
region : ap-south-1 : env : ['AWS_REGION', 'AWS_DEFAULT_REGION']For an assume-role profile, TYPE shows assume-role after the CLI resolves role credentials:
aws configure list --profile glc-expired-lab-roleNAME : VALUE : TYPE : LOCATION
profile : glc-expired-lab-role : manual : --profile
access_key : ****************ZQZH : assume-role :
secret_key : ****************Y3vL : assume-role :
region : ap-south-1 : env : ['AWS_REGION', 'AWS_DEFAULT_REGION']List credential-related environment variables when LOCATION is env or when a script exported credentials earlier in the day:
env | grep '^AWS_'Look for:
AWS_ACCESS_KEY_IDstarting withASIAAWS_SESSION_TOKENset from exported credentials, a CI job, or a priorget-session-tokenrunAWS_PROFILEpointing at a profile whose underlying SSO or login session expired
Check expiration on a session you created with get-session-token or assume-role by reading the Expiration field in the JSON response. AWS does not store that timestamp in aws configure list; inspect the CLI cache when debugging role sessions.
Cached credential locations by source:
~/.aws/cli/cache— AssumeRole sessions~/.aws/sso/cache— IAM Identity Center authentication tokens~/.aws/login/cache—aws loginsessions (CLI v2.32+)
Refresh IAM Identity Center and login credentials
IAM Identity Center profiles use a cached SSO session to obtain short-lived AWS role credentials. The CLI refreshes those AWS credentials automatically while the SSO session remains valid. When the SSO session itself expires or becomes invalid, sign in again:
aws sso login --profile corp-ssoThe SSO authentication token lives under ~/.aws/sso/cache. When that session expires, the next API call may return ExpiredToken or a refresh error such as:
refresh cached SSO token failed, failed to refresh cached credentials, the SSO session has expired or is invalidRecommended ~/.aws/config layout uses a shared sso-session block:
[profile corp-sso]
sso_session = corp-sso
sso_account_id = 123456789012
sso_role_name = AdministratorAccess
region = ap-south-1
[sso-session corp-sso]
sso_start_url = https://my-org.awsapps.com/start
sso_region = ap-south-1
sso_registration_scopes = sso:account:accessAWS CLI v2.32 and later also supports aws login for Management Console–backed workstation sessions. Cached credentials and refresh metadata live under ~/.aws/login/cache; the CLI refreshes temporary credentials while the refresh token remains valid. When the login cache is missing or expired, the CLI may report:
aws sts get-caller-identityaws: [ERROR]: Error loading login session token: Unable to load a existing login session for session arn:aws:iam::123456789012:root, Please reauthenticate with 'aws login'.This is not an STS ExpiredToken response—the local aws login session is missing or expired. Sign in again, then retry the AWS command:
aws loginAfter SSO or login refresh, confirm identity with the profile in use:
aws sts get-caller-identity --profile corp-ssoTerraform workflows that export credentials into the shell should refresh the login or SSO session first, then export only the credentials that profile resolves to; see Fix Terraform AWS ExpiredToken for the provider-side error text.
Refresh AssumeRole credentials
Assume-role profiles in ~/.aws/config use a source_profile (or another credential source) to call sts:AssumeRole. The CLI caches the resulting temporary credentials under ~/.aws/cli/cache.
While the cache entry is valid, calls succeed. When cached role credentials expire, the CLI tries to assume the role again using the source profile. If the source session is still valid, refresh is silent. If the source credentials expired, the next call returns ExpiredToken.
Example profile chain:
[profile glc-expired-lab-session]
aws_access_key_id = ASIAIOSFODNN7EXAMPLE
aws_secret_access_key = ***
aws_session_token = ***
[profile glc-expired-lab-role]
role_arn = arn:aws:iam::123456789012:role/glc-expired-lab-role
source_profile = glc-expired-lab-session
region = ap-south-1
duration_seconds = 900When the source session profile holds expired ASIA keys, the role profile cannot assume the role. Even aws configure list may surface the failure while resolving credentials:
aws configure list --profile glc-expired-lab-roleaws: [ERROR]: An error occurred (ExpiredToken) when calling the AssumeRole operation: The security token included in the request is expired
NAME : VALUE : TYPE : LOCATION
profile : glc-expired-lab-role : manual : --profileRefresh the source first. Issue a new session token on a long-term profile, update the [glc-expired-lab-session] block with the new access key, secret key, and session token from the JSON output, then call the role profile again:
aws sts get-session-token --profile glc-expired-lab-base --duration-seconds 900Update the [glc-expired-lab-session] block with the new access key, secret key, and session token from the JSON output, then verify:
aws sts get-caller-identity --profile glc-expired-lab-role{
"UserId": "AROAU7QAIUYJEH4KAMJLO:botocore-session-1790529898",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/glc-expired-lab-role/botocore-session-1790529898"
}Clearing ~/.aws/cli/cache forces a fresh AssumeRole call after the source credentials are valid again. Deleting cache files alone does not extend an expired session.
Remove stale environment variables
Many teams export credentials once and reuse the shell for hours. When the underlying STS session ends, exported AWS_* variables still point at expired material.
Reproduce the failure with only environment credentials and no shared-credentials fallback:
export AWS_ACCESS_KEY_ID='ASIA...'
export AWS_SECRET_ACCESS_KEY='***'
export AWS_SESSION_TOKEN='***'
aws sts get-caller-identityAfter expiration, the same exports return:
aws sts get-caller-identityaws: [ERROR]: An error occurred (ExpiredToken) when calling the GetCallerIdentity operation: The security token included in the request is expiredRemove the stale triplet before refreshing:
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKENObtain a new session from a long-term profile (only valid when the profile uses IAM user access keys, not SSO or assume-role-only profiles). Export the three values from the GetSessionToken response—not from aws configure export-credentials on the long-term profile, which resolves static AKIA keys instead of the STS session you just created:
read AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN < <(
aws sts get-session-token --profile glc-expired-lab-base --duration-seconds 900 --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' --output text
)
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKENThe environment now holds the new STS credential triplet returned by GetSessionToken.
After a fresh session is in the environment, identity checks succeed again:
aws sts get-caller-identity{
"UserId": "AIDAU7QAIUYJA7FMGBFY7",
"Account": "123456789012",
"Arn": "arn:aws:iam::123456789012:user/glc-expired-lab-user"
}If AWS_PROFILE is set alongside exported variables, remember that environment variables override profile credentials for the default chain. Unset the exports when switching back to a named profile.
Check clock only if signature errors also appear
If the error code is specifically ExpiredToken, refresh the temporary credentials first. Clock problems more commonly appear as request or signature timing failures. Check NTP only when the error also mentions request time, signature expiry, or clock skew:
timedatectl statusIf System clock synchronized is no, enable NTP or run chronyc makestep, then refresh credentials. NTP sync alone does not replace renewing an expired STS session when AWS returns ExpiredToken.
Verify with STS
aws sts get-caller-identity confirms which principal the CLI sends after a refresh. Run it in the same shell, with the same AWS_PROFILE and environment variables as the failing command.
aws sts get-caller-identityWhen authentication succeeds, the response includes Account, UserId, and Arn. When temporary credentials are still expired, the call returns ExpiredToken again — the refresh step did not reach the provider the CLI actually uses.
After identity checks pass, retry the original command (aws s3 ls, terraform plan, or another API call). If the error changes to AccessDenied, authentication succeeded and authorization deserves attention on a different page.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
ExpiredToken right after lunch in the same terminal |
Exported AWS_SESSION_TOKEN from an earlier session |
unset the three env vars; issue a new STS session and export its Credentials fields |
ExpiredToken in AWS CLI on an EC2 instance that has an IAM role |
Stale exported temporary credentials override the auto-refreshing instance-role credentials | Run aws configure list; if LOCATION shows env, unset the three credential variables and retry |
Role profile fails; source profile uses ASIA keys |
Source session expired; AssumeRole cannot refresh | Renew source session credentials, then call the role profile |
aws configure list shows env but profile was refreshed |
Stale environment override | unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN |
| SSO refresh error mentioning cached SSO token | IAM Identity Center portal session expired | aws sso login --profile <name> |
Please reauthenticate with 'aws login' |
CLI login cache cleared or expired | aws login |
Rotated AKIA key; still ExpiredToken |
Long-term key rotation does not renew existing STS sessions | Refresh the temporary session, not the static key |
Error changed to InvalidClientTokenId |
Incomplete or mismatched triplet after partial unset | Export all three fields or use InvalidClientTokenId guide |
Normally you should not manually copy EC2 instance-role credentials into environment variables. The instance metadata credential provider refreshes role credentials automatically; exported copies do not.
Summary
ExpiredToken means the temporary credential set reached its STS expiration time. The CLI is still sending ASIA keys and a session token, but AWS will not honor them until the underlying session is renewed.
aws configure list shows whether environment variables, an assume-role profile, or a login/SSO-backed profile supplied the keys. Refresh the source of the temporary credentials — IAM Identity Center login, aws login, a session profile used by AssumeRole, or exported environment variables — rather than editing static access keys or bumping profile duration for a session that was already issued.
After refresh, aws sts get-caller-identity confirms the principal AWS sees. When the error flips to AccessDenied, authentication succeeded and IAM authorization is the next layer to inspect.
References
- AWS CLI — Environment variables — credential environment variables override profile credentials
- AWS CLI — Using an IAM role in the AWS CLI — assume-role profiles and cache refresh
- AWS CLI — Configuring IAM Identity Center authentication —
aws sso loginandsso-sessionblocks - AWS STS API Reference — GetSessionToken — session duration and expiration
- AWS Security Token Service API Reference — GetCallerIdentity
Frequently Asked Questions
How long do STS credentials last?
GetSessionToken credentials created from long-term IAM-user credentials can last from 15 minutes up to 36 hours (default 12 hours). For root or account credentials, the maximum is one hour. AssumeRole sessions normally last from 15 minutes up to the target role's configured maximum, which can be as high as 12 hours; role chaining is limited to one hour. In every case, the issued credentials have a fixed expiration timestamp—changing a profile later does not extend an existing session.
Does rotating an access key fix ExpiredToken?
No. Rotating a long-term AKIA access key replaces static credentials. ExpiredToken applies to an existing temporary session (ASIA plus session token). Issue a new STS session or refresh SSO/login instead.
Why does a profile keep using old credentials?
Environment variables override profile credentials when they are set. A profile can look correct in ~/.aws/credentials while the shell still exports an expired triplet from an earlier job. Run aws configure list and env | grep '^AWS_' in the failing shell; unset stale exports before testing the profile.

