| Tested on | Ubuntu 26.04 LTS (Resolute Raccoon) |
|---|---|
| Package | terraform 1.16.1hashicorp/aws 6.63.0awscli 2.36.38 |
| Applies to | Any host with Terraform and the AWS provider; examples use ap-south-1 |
| Privilege | AWS identity that can call sts:GetCallerIdentity; normal user on the workstation |
| Scope | Diagnose and fix ExpiredToken and related STS session failures from the HashiCorp AWS provider or S3 remote state backend during terraform plan or apply — stale AWS_SESSION_TOKEN environment variables, expired IAM Identity Center (SSO) sessions, aws configure export-credentials exports, and temporary credentials from sts:GetSessionToken or sts:AssumeRole. Does not cover missing credentials (No valid credential sources found), IAM permission denials (UnauthorizedOperation), or VPC destroy dependency errors. |
| Related guides | Install AWS CLI on Ubuntu |
Terraform reached AWS, but the provider rejected your session before it could read any resource:
Error: Retrieving AWS account details: validating provider credentials: retrieving caller identity from STS: operation error STS: GetCallerIdentity, https response error StatusCode: 403, RequestID: …, api error ExpiredToken: The security token included in the request is expiredThe AWS CLI prints the same root cause in shorter form:
An error occurred (ExpiredToken) when calling the GetCallerIdentity operation: The security token included in the request is expiredThat is different from missing credentials and different from IAM denying an API call. AWS recognized the credential shape but the STS session is past its expiration time.
What Terraform ExpiredToken means
- Your access key id, secret key, and session token were valid at some point, but the session token lifetime has ended
- Terraform fails during provider configuration or the first API call — often on
sts:GetCallerIdentitybefore any resource is planned - The fix is to refresh or remove the temporary credentials, not to edit
.tffiles
No valid credential sources found — see Fix Terraform AWS credentials error. If AWS authenticates you but denies a specific API action, see Fix Terraform AWS UnauthorizedOperation.
Related errors you may see instead of ExpiredToken:
| Error | What it usually means |
|---|---|
ExpiredToken |
STS session token is past its expiration timestamp |
InvalidClientTokenId |
Token is malformed, revoked, or a leftover AWS_SESSION_TOKEN does not match the access key |
SignatureDoesNotMatch … Signature expired |
Workstation clock is far behind AWS — sync NTP before refreshing credentials |
refresh cached SSO token failed … SSO session has expired |
IAM Identity Center portal session expired — run aws sso login again |
Find which AWS credentials Terraform is using
The HashiCorp AWS provider can obtain credentials from provider configuration parameters, environment variables, shared credentials files, shared configuration files, container credentials, or instance profile credentials — in that order of precedence.
Stale AWS_* environment variables are especially important to check when the provider does not explicitly select a profile, because environment credentials take precedence over credentials that would otherwise come from shared AWS files.
Check the active identity in the same shell that runs Terraform:
aws sts get-caller-identityIf that fails with ExpiredToken or InvalidClientTokenId, Terraform will fail too — fix the shell first.
List credential-related environment variables:
env | grep '^AWS_'What to look for:
AWS_ACCESS_KEY_IDstarting withASIA— temporary credentials that include a session tokenAWS_SESSION_TOKENset from an oldeval "$(aws configure export-credentials …)"or CI jobAWS_PROFILEpointing at an SSO profile whose browser login expired
When you use a named profile in the provider block, the provider uses that profile rather than environment credentials. Confirm the profile name matches what you logged into:
provider "aws" {
region = "ap-south-1"
profile = "corp-sso"
}Fix Terraform ExpiredToken
Most fixes follow the same pattern: identify where the credentials came from, renew the source session if needed, then retry Terraform in the same shell.
Stale AWS_SESSION_TOKEN or exported STS credentials
Many teams export credentials once and reuse the shell all day. Temporary keys expire when the underlying STS session ends.
Symptom: aws sts get-caller-identity worked earlier in the same terminal; both CLI and Terraform now return ExpiredToken or InvalidClientTokenId.
aws configure export-credentials exports whatever credentials the CLI currently resolves for a profile. It does not renew an already-expired STS session by itself. Renew the source credentials first, then export:
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKENReplace corp-sso with the profile that supplies your temporary credentials:
aws sso login --profile corp-ssoExport the refreshed session into environment variables Terraform can read:
eval "$(aws configure export-credentials --profile corp-sso --format env)"Confirm the new identity:
aws sts get-caller-identityRun plan again in that same shell:
terraform planWithout --profile, export-credentials uses the default profile. For scripts and CI, chain login, export, and Terraform in one step:
aws sso login --profile corp-sso && eval "$(aws configure export-credentials --profile corp-sso --format env)" && terraform planIf the underlying profile itself still holds expired temporary credentials, export-credentials cannot renew them — fix the source (SSO login, aws login, or a new sts:AssumeRole call) before exporting.
The same export pattern appears in cloud guides such as deploy EKS with Terraform — refresh credentials in every shell before terraform init, plan, or apply.
IAM Identity Center / AWS SSO session expired
Teams using IAM Identity Center should use the recommended sso-session configuration in ~/.aws/config so AWS SDKs can refresh access tokens while the portal session remains valid:
[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:accessWhen the IAM Identity Center portal session itself expires, the provider may report:
refresh cached SSO token failed, failed to refresh cached credentials, the SSO session has expired or is invalidLog in again:
aws sso login --profile corp-ssoConfirm identity with that profile:
aws sts get-caller-identity --profile corp-ssoPoint Terraform at the profile:
provider "aws" {
region = "ap-south-1"
profile = "corp-sso"
}With the sso-session format above, the AWS SDK can refresh credentials automatically while the portal session is still valid. Run aws sso login --profile corp-sso again after the portal session itself expires.
Alternatively, export standard environment variables after login:
eval "$(aws configure export-credentials --profile corp-sso --format env)"
terraform planStale exported temporary credentials override your long-term profile
You may have valid long-term credentials in ~/.aws/credentials but still have an older temporary credential set exported in the shell:
env | grep '^AWS_'Example output:
AWS_ACCESS_KEY_ID=ASIAEXAMPLE
AWS_SECRET_ACCESS_KEY=example-secret
AWS_SESSION_TOKEN=example-session-tokenBecause environment credentials take precedence over shared credential files when no provider profile is explicitly selected, Terraform uses this expired temporary credential set instead of the long-term credentials in ~/.aws/credentials.
Clear the stale export and verify identity:
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
aws sts get-caller-identityWhen identity checks succeed, re-run Terraform:
terraform planCredentials expired during terraform apply
Temporary credential lifetime depends on how the credentials were issued. AssumeRole sessions can range from 15 minutes up to the role's configured maximum of 12 hours, while other STS operations have different limits.
A long terraform apply on a large stack can outlive the session if credentials were exported at the start of the day.
Prevention:
- Refresh credentials immediately before
terraform apply, not only beforeplan - Prefer a provider
profilebacked by refreshable IAM Identity Center credentials over staticAWS_*exports when your workflow allows - In CI, fetch credentials in the same job step that runs Terraform — do not reuse artifacts from an earlier stage
If terraform apply fails after some resources were created, refresh the credentials and run terraform plan again. Terraform refreshes the current resource state and shows what remains to be changed; normally you do not need to destroy resources that were successfully created.
Is ExpiredToken coming from the provider or S3 backend?
ExpiredToken can appear while Terraform talks to AWS in two different places.
Provider credentials — errors mention Retrieving AWS account details, GetCallerIdentity, or a specific AWS resource API (for example ec2:DescribeVpcs). Troubleshoot provider credentials using the steps above.
S3 backend credentials — errors mention the S3 backend, state persistence, PutObject, GetObject, or acquiring or releasing a state lock. The credentials used by the remote backend have expired even though your provider block might still be valid.
When the backend is the source:
- Refresh AWS credentials the same way —
aws sso login, thenexport-credentialsif you rely on environment variables - Retry the Terraform operation (
terraform init,plan, orapply) - Do not run
terraform force-unlockor edit state solely because credentials expired — renew credentials first
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
ExpiredToken on plan or apply |
Exported AWS_SESSION_TOKEN past expiration |
Renew source session (aws sso login), then eval "$(aws configure export-credentials --profile <name> --format env)" |
ExpiredToken although valid credentials exist in ~/.aws/credentials |
Stale temporary credential trio exported in shell | unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN |
aws sts works, Terraform fails |
Different shell, profile, or env vars | Run get-caller-identity in the Terraform shell; align AWS_PROFILE and provider profile |
| SSO profile in provider block fails | IAM Identity Center portal session expired | aws sso login --profile <name> |
refresh cached SSO token failed |
Same as expired portal session | Re-login; export credentials if needed |
| Worked at plan, failed at apply | Session expired between commands | Refresh credentials immediately before apply |
SignatureDoesNotMatch / Signature expired |
VM clock behind AWS | Check system time with timedatectl status and restore time synchronization |
| Error mentions S3 backend or state lock | Backend credentials expired | Refresh credentials; retry — do not force-unlock state for auth expiry alone |
| CI fails on schedule only | Injected credentials from prior pipeline stage | Generate credentials in the same step as terraform |
For broader Terraform failure stages, see Terraform troubleshooting.
Summary
ExpiredToken during terraform plan or apply means Terraform signed AWS requests with a session token that is no longer valid. That is a credential lifetime problem, not a syntax error in your Terraform configuration.
Start in the same shell that runs Terraform: run aws sts get-caller-identity and inspect AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN. When exports are stale, renew the underlying session (aws sso login or equivalent), then run eval "$(aws configure export-credentials --profile <name> --format env)". When a stale temporary credential trio in the shell overrides long-term keys in ~/.aws/credentials, unset all three AWS_* variables.
Use the recommended sso-session profile format so the AWS SDK can refresh credentials while the IAM Identity Center portal session remains valid. For long applies, refresh credentials right before terraform apply. When the error mentions the S3 backend instead of a provider API, renew the same AWS credentials and retry — do not modify state locks solely because auth expired.
References
- Terraform AWS provider — authentication
- AWS CLI
configure export-credentials - IAM Identity Center credential flows
- AWS STS temporary credentials
- HashiCorp — ExpiredToken during long-running applies
Frequently Asked Questions
Is ExpiredToken the same as No valid credential sources found?
No. No valid credential sources found means Terraform could not find any credentials. ExpiredToken means credentials were present but the session token lifetime ended.
Why does aws sts work in one terminal but Terraform fails in another?
Each shell has its own environment. SSO logins and export-credentials do not propagate automatically. Export or log in in the shell that runs Terraform.
Should I put access keys in the provider block to avoid expiration?
No. Long-lived keys in code expire rotation policies and widen blast radius. Refresh temporary sessions or use SSO profiles instead.
Does terraform apply automatically refresh SSO tokens?
When you use a provider profile backed by IAM Identity Center with an sso-session block, the AWS SDK can refresh access tokens while the portal session remains valid. Static AWS_* environment variables do not auto-refresh — re-export them.
Plan succeeded yesterday; today both plan and apply fail with ExpiredToken
Your exported session expired overnight. Unset AWS_* variables, log in again, export fresh credentials, and retry.

