ERROR REFERENCE
The security token included in the request is expired (ExpiredToken)
AWS rejected the request because the temporary credentials were no longer valid when it arrived. This is a credential-lifetime or clock problem — not a permissions problem and not a template problem.
WHAT IT MEANS
What this error means
Temporary AWS credentials — SSO sessions, assumed roles, OIDC sessions in
CI — carry an expiry. When a request signed with expired credentials
reaches AWS, you get ExpiredToken or
ExpiredTokenException. The common shapes:
- A stale local session. An
aws sso loginfrom this morning, a long-lived shell exporting oldAWS_SESSION_TOKENvalues, or a cached named-profile session. - A long CI job outliving its session. OIDC-assumed roles default to a 1-hour session; a build+deploy job that runs longer fails at whatever AWS call lands after expiry.
- Rotated or copy-pasted credentials in CI secrets that included a session token from a temporary session.
- Clock skew. A variant message —
Signature expired: ... is now earlier than ...— means the machine's clock is off far enough that AWS treats the signature as stale. No credential rotation will fix a wrong clock.
FIX
How to fix it
- Identify which environment failed — local shell, laptop SSO session, or CI runner. The fix is different for each.
-
Local: refresh the session and clear stale variables:
aws sso login --profile YOUR_PROFILE # or, if credentials were exported by hand: unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN aws sts get-caller-identity # confirm the refreshed identity -
CI with OIDC: check how long the job runs before the
failing call. If it exceeds the session, raise the role's maximum session
duration and pass a matching
role-duration-secondstoaws-actions/configure-aws-credentials, or re-invoke the credentials action right before the deploy step. -
CI with static secrets: if the stored secret includes an
AWS_SESSION_TOKEN, it came from a temporary session and will keep expiring. Replace it with OIDC or a proper long-lived mechanism. -
For
Signature expired ... is now earlier than ...: compare the two timestamps in the message. A gap of more than a few minutes means the runner's clock is skewed — sync it with NTP (self-hosted runners and containers with a frozen clock are the usual offenders) instead of touching credentials. -
Confirm the deployment actually picks up the fresh credentials
(no stale
AWS_*environment variables shadowing the profile) before retrying.
AUTOMATE THE TRIAGE
Diagnose this automatically
SAM Doctor recognizes ExpiredToken, the expired-security-token
phrasing, and the clock-skew variant (high confidence), and separates them
from real permission denials. Runs locally; no AWS access, no log upload.
python -m pip install sam-doctor
sam-doctor diagnose deployment.log --format markdown
RELATED
Related errors
- Not authorized to perform: sts:AssumeRoleWithWebIdentity — the session never existed, rather than expiring.
- no basic auth credentials — the ECR variant: a 12-hour registry token that expired mid-job.
- Rate exceeded (Throttling) — another transient failure that retries can mask.