Report #54703
[bug\_fix] ExpiredToken: The provided token has expired
Remove the hardcoded AWS\_ACCESS\_KEY\_ID, AWS\_SECRET\_ACCESS\_KEY, and AWS\_SESSION\_TOKEN environment variables or code references, and instead rely on the AWS SDK credential provider chain with an IAM role configured in ~/.aws/config using \`role\_arn\` and \`source\_profile\`. When assuming a role via the shared config file \(using \`role\_arn\`\), the AWS SDK \(boto3/botocore\) automatically uses the AssumeRoleProvider which handles STS AssumeRole calls and refreshes the temporary credentials before they expire \(by default 1 hour\). If you must use explicit session tokens in code, implement a custom credential provider that calls STS AssumeRole with a duration and refreshes the credentials when expiration approaches. The root cause is that temporary credentials obtained via STS AssumeRole or GetSessionToken have a fixed expiration \(1 hour by default for assumed roles, up to 36 hours for session tokens\), and the SDK does not auto-refresh credentials that were passed explicitly via environment variables or constructor arguments; it only auto-refreshes when it manages the credential provider itself via the shared config or instance metadata.
Journey Context:
A developer sets up a CI/CD pipeline that deploys to AWS. They assume a cross-account role manually using \`aws sts assume-role\` in a shell script, export the returned AccessKeyId, SecretAccessKey, and SessionToken as environment variables, then run a Python script using boto3. The script runs successfully for exactly 60 minutes, then starts failing with 'ExpiredToken: The provided token has expired'. The developer checks the timestamps and realizes the credentials expired exactly 1 hour after the assume-role call. They try increasing the duration-seconds in the assume-role call to 3600 \(max for assumed roles is actually 12 hours, but default is 1 hour\), but realize this just delays the problem. They investigate why \`aws s3 ls\` works indefinitely on their laptop but the CI script fails. They learn that when using \`aws configure\` with a \`role\_arn\` in the config file, the AWS CLI and boto3 use an internal credential provider \(AssumeRoleCredentialFetcher\) that automatically calls STS AssumeRole again before the current credentials expire, creating a seamless rotation. They refactor the CI/CD to use a profile with \`role\_arn\` and \`web\_identity\_token\_file\` \(or source\_profile\) instead of manual env vars, and the expiration errors stop because the SDK now manages the lifecycle.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T22:18:55.600236+00:00— report_created — created