Report #29472
[bug\_fix] ExpiredToken: The security token included in the request is expired
When using temporary credentials from STS AssumeRole, ensure your application uses the AWS SDK's credential provider chain that automatically refreshes credentials, or manually implement credential refresh logic using the \`Expiration\` timestamp from the AssumeRole response. For long-lived processes, use the SDK's \`assume\_role\` credential provider in the shared config file \(\`~/.aws/config\`\) with \`role\_arn\` and \`source\_profile\`, which handles automatic refresh, or implement a custom credentials provider that calls STS AssumeRole before the expiration \(typically 15 minutes to 1 hour depending on the MaxSessionDuration\).
Journey Context:
You have a data processing job that runs for 6 hours on an EC2 instance. It needs to write results to an S3 bucket in a different AWS account. You set up cross-account access using STS AssumeRole, and you wrote a startup script that calls \`aws sts assume-role\` and exports the resulting \`AWS\_ACCESS\_KEY\_ID\`, \`AWS\_SECRET\_ACCESS\_KEY\`, and \`AWS\_SESSION\_TOKEN\` as environment variables before launching the Python application. The job starts successfully and writes data for about an hour, then suddenly starts throwing \`ExpiredToken\` errors from the S3 client. You check the timestamp when you assumed the role - it was exactly 1 hour ago. You realize that STS temporary credentials expire after the DurationSeconds specified \(default 3600 seconds/1 hour if not specified\), and your long-running process has no way to refresh them. You search for solutions and find that the AWS SDK for Python \(boto3\) has a \`RefreshableCredentials\` class or you can use the \`assume\_role\` configuration in \`~/.aws/config\` which handles the refresh automatically. You modify your setup to use the shared config file with \`role\_arn\` and \`source\_profile\` instead of manual environment variables, and boto3 automatically refreshes the credentials before they expire by calling STS AssumeRole again. The job now runs the full 6 hours without token expiration because the SDK's built-in credential provider chain handles the refresh logic transparently.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T03:51:43.703242+00:00— report_created — created