AWS Security Token Service (STS) & Temporary Credentials
Overview
AWS Security Token Service (STS) is a web service that enables you to request temporary, limited-privilege credentials for IAM users or federated users. These credentials work almost identically to long-term access keys but expire automatically after a specified duration.
Temporary credentials are foundational to AWS security best practices. They eliminate the need to distribute or embed long-term credentials, reduce the blast radius of compromised credentials, and enable advanced features like cross-account access and identity federation.
Core Concept
Temporary credentials consist of three components:
- Access Key ID - Identifies the credential
- Secret Access Key - Used for signing requests
- Session Token - Required for all API calls using temporary credentials
All three must be included when making AWS API calls with temporary credentials.
STS questions often focus on which API to use for specific scenarios: AssumeRole for cross-account access, AssumeRoleWithSAML for enterprise federation, and AssumeRoleWithWebIdentity for mobile/web apps.
Architecture Diagram

Key Concepts
How Temporary Credentials Work
Temporary Credentials Lifecycle
Request Phase:
- User/application calls STS API (e.g., AssumeRole)
- STS validates the request against trust policy
- STS returns temporary credentials
Usage Phase:
- Application uses credentials for AWS API calls
- Credentials include session token in every request
- AWS validates credentials on each request
Expiration Phase:
- Credentials expire automatically (no revocation needed)
- Application must request new credentials before expiration
- Cannot extend existing credentials - must request new ones
Credential Duration
Credential Duration Limits
| STS API | Default Duration | Minimum | Maximum |
|---|---|---|---|
| AssumeRole | 1 hour | 15 minutes | 12 hours* |
| AssumeRoleWithSAML | 1 hour | 15 minutes | 12 hours* |
| AssumeRoleWithWebIdentity | 1 hour | 15 minutes | 12 hours* |
| GetSessionToken | 12 hours | 15 minutes | 36 hours |
| GetFederationToken | 12 hours | 15 minutes | 36 hours |
*Maximum duration can be set per role (up to 12 hours)
STS API Operations
AssumeRole
Purpose: Assume an IAM role within your account or cross-account
Use Cases:
- Cross-account access to resources
- Privilege escalation for specific tasks
- Temporary elevated permissions
Requirements:
- Caller must have
sts:AssumeRolepermission - Role must have trust policy allowing the caller
- Optional: MFA requirement in trust policy
Returns: AccessKeyId, SecretAccessKey, SessionToken, Expiration
AssumeRoleWithSAML
Purpose: Exchange SAML assertion for temporary credentials
Use Cases:
- Enterprise single sign-on (SSO)
- Active Directory Federation Services (ADFS)
- Corporate identity provider integration
Requirements:
- Valid SAML 2.0 assertion from trusted IdP
- IAM SAML identity provider configured
- Role trust policy allowing SAML federation
No IAM User Required: Users don't need IAM accounts
AssumeRoleWithWebIdentity
Purpose: Exchange web identity token for temporary credentials
Use Cases:
- Mobile applications
- Single-page web applications
- Social login (Amazon, Facebook, Google)
- OIDC-compatible identity providers
Recommended: Use Amazon Cognito instead for simplified integration
Requirements:
- Token from web identity provider
- IAM OIDC identity provider configured
- Role trust policy allowing the IdP
GetSessionToken
Purpose: Get temporary credentials for an existing IAM user
Use Cases:
- Add MFA protection to IAM user credentials
- CLI/SDK usage requiring temporary credentials
- When user already has long-term credentials
Key Difference: Used by IAM users, not for role assumption
GetFederationToken
Purpose: Get credentials for a federated user (custom federation)
Use Cases:
- Custom identity broker implementations
- Proxy/broker services that manage federation
- Server-side applications managing user access
Note: Caller determines the federated user's permissions (subset of caller's permissions)
How It Works
Cross-Account Access with AssumeRole

Step 1: Create Role in Target Account
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}Step 2: Grant AssumeRole Permission in Source Account
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::222222222222:role/CrossAccountRole"
}
]
}Step 3: Assume the Role
# Assume the role
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/CrossAccountRole \
--role-session-name MySession \
--duration-seconds 3600
# Response includes temporary credentials:
# {
# "Credentials": {
# "AccessKeyId": "ASIA...",
# "SecretAccessKey": "...",
# "SessionToken": "...",
# "Expiration": "2024-01-15T13:00:00Z"
# },
# "AssumedRoleUser": {
# "AssumedRoleId": "AROA...:MySession",
# "Arn": "arn:aws:sts::222222222222:assumed-role/CrossAccountRole/MySession"
# }
# }
# Use the credentials
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...
# Now commands run as the assumed role
aws s3 ls s3://bucket-in-account-b/Using AssumeRole with MFA
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/SensitiveRole \
--role-session-name AdminSession \
--serial-number arn:aws:iam::111111111111:mfa/username \
--token-code 123456 \
--duration-seconds 3600Federation with SAML
aws sts assume-role-with-saml \
--role-arn arn:aws:iam::123456789012:role/SAMLRole \
--principal-arn arn:aws:iam::123456789012:saml-provider/ExampleProvider \
--saml-assertion file://saml-assertion.txt \
--duration-seconds 3600Use Cases
Use Case 1: EC2 Instance Role
Scenario: Application on EC2 needs to access S3 and DynamoDB.
Solution: Attach an IAM role to the EC2 instance.
How EC2 Instance Roles Work
- Instance metadata service provides temporary credentials
- AWS SDKs automatically retrieve and refresh credentials
- Credentials rotate automatically (typically every 6 hours)
- No credentials stored on the instance
Endpoint: http://169.254.169.254/latest/meta-data/iam/security-credentials/role-name
Use Case 2: Cross-Account S3 Access
Scenario: Development team in Account A needs read access to production logs in Account B.
Solution:
- Account B creates role with S3 read permissions and trust policy for Account A
- Account A grants developers permission to assume the role
- Developers assume role to access logs, credentials expire after session
Use Case 3: CI/CD Pipeline
Scenario: Jenkins needs to deploy to AWS without long-term credentials.
Solution:
- Create IAM role with deployment permissions
- Configure Jenkins to assume role using OIDC federation or instance role
- Each deployment gets fresh, short-lived credentials
Use Case 4: Mobile App with Cognito
Scenario: Mobile app needs user-specific access to S3 buckets.
Solution:
- User authenticates with Amazon Cognito
- Cognito exchanges identity token for temporary AWS credentials
- App uses credentials scoped to that user's data
Best Practices
STS Best Practices
- Use Shortest Practical Duration - Minimize exposure window
- Always Require MFA for Sensitive Roles - Add condition to trust policy
- Use External ID for Third-Party Access - Prevent confused deputy problem
- Log All AssumeRole Calls - CloudTrail captures all STS API calls
- Use Regional Endpoints - Reduce latency and improve availability
- Implement Credential Refresh - Handle expiration gracefully in applications
External ID for Third-Party Access
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::THIRD-PARTY-ACCOUNT:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "unique-external-id-12345"
}
}
}
]
}Common Exam Scenarios
STS Exam Scenarios
| Scenario | STS API | Why |
|---|---|---|
| User in Account A needs access to S3 in Account B | AssumeRole | Cross-account access via IAM role |
| Enterprise users login via Active Directory | AssumeRoleWithSAML | SAML 2.0 federation with ADFS |
| Mobile app users authenticate with Google | AssumeRoleWithWebIdentity (or Cognito) | OIDC federation for social login |
| IAM user needs MFA-protected temporary credentials | GetSessionToken | Adds MFA to existing IAM user |
| Application on EC2 needs DynamoDB access | Automatic (Instance Role) | EC2 instance role provides credentials automatically |
| Third-party SaaS needs access to your S3 | AssumeRole with External ID | Prevents confused deputy problem |
| Lambda function needs cross-account access | AssumeRole (in code) | Lambda execution role + assume target role |
Common Pitfalls
Pitfall 1: Forgetting the Session Token
Mistake: Using only AccessKeyId and SecretAccessKey from temporary credentials.
Why it fails:
- Temporary credentials REQUIRE the session token
- API calls will fail with "InvalidAccessKeyId" error
- Easy to miss when copying credentials manually
Correct Approach:
- Always include all three: AccessKeyId, SecretAccessKey, SessionToken
- Use AWS SDKs that handle this automatically
- Check environment variables include AWS_SESSION_TOKEN
Pitfall 2: Not Handling Credential Expiration
Mistake: Assuming credentials last forever or not refreshing them.
Why it fails:
- Temporary credentials expire (default 1 hour)
- Long-running applications will suddenly fail
- No warning before expiration
Correct Approach:
- Implement credential refresh logic
- Use AWS SDKs with built-in refresh (instance roles, credential providers)
- Request new credentials before expiration
Pitfall 3: Overly Permissive Trust Policies
Mistake: Using "Principal": "*" in role trust policies.
Why it's dangerous:
- Any AWS account could potentially assume the role
- No external ID means any caller can assume
- Defeats the purpose of role-based access
Correct Approach:
- Specify exact principal ARNs
- Require External ID for third-party access
- Require MFA for sensitive roles
- Use conditions to further restrict
Pitfall 4: Confused Deputy Problem
Mistake: Not using External ID when granting cross-account access to third parties.
Why it matters:
- Malicious actor could trick third-party service into accessing your resources
- Third-party service might accidentally access wrong customer's data
- Common security vulnerability in multi-tenant systems
Correct Approach:
- Always use External ID for third-party access
- Generate unique, unpredictable External IDs
- Validate External ID in trust policy
Test Your Knowledge
Which STS API should be used for cross-account access between AWS accounts?
What components make up temporary security credentials?
An enterprise wants to allow employees to access AWS using their Active Directory credentials. Which STS API should they use?
What is the purpose of External ID in a role trust policy?
Related Services
Quick Reference
STS API Comparison
STS API Quick Reference
| API | Use Case | Requires IAM User? |
|---|---|---|
| AssumeRole | Cross-account access, role switching | No (caller needs permission) |
| AssumeRoleWithSAML | Enterprise SSO via SAML | No |
| AssumeRoleWithWebIdentity | Mobile/web app social login | No |
| GetSessionToken | MFA for IAM user credentials | Yes |
| GetFederationToken | Custom identity broker | Yes |
STS Endpoints
Global: https://sts.amazonaws.com
US East: https://sts.us-east-1.amazonaws.com
EU West: https://sts.eu-west-1.amazonaws.com
AP Tokyo: https://sts.ap-northeast-1.amazonaws.com
Regional endpoints reduce latency - credentials work globallyCLI Commands
# Assume a role
aws sts assume-role --role-arn <role-arn> --role-session-name <name>
# Assume role with MFA
aws sts assume-role --role-arn <role-arn> --role-session-name <name> \
--serial-number <mfa-arn> --token-code <code>
# Get session token (with MFA)
aws sts get-session-token --serial-number <mfa-arn> --token-code <code>
# Get caller identity
aws sts get-caller-identity
# Decode authorization message
aws sts decode-authorization-message --encoded-message <message>