Simplify access to external services using AWS IAM Outbound Identity Federation
IAM outbound identity federation is most interesting for teams that already run workloads on AWS but must reach external APIs, SaaS platforms, or self-hosted systems without embedding static secrets. The architectural shift is simple in concept but important in practice: AWS becomes the issuer of a short-lived token, while the external service becomes the verifier and relying party.
That changes how access is designed at the boundary. Instead of distributing API keys across workloads, engineers must align on issuer trust, audience validation, claim mapping, and token lifetime. The external system also needs a JWKS retrieval path and logic to reject unexpected issuers or algorithms, so integration now includes cryptographic verification and key-rotation handling rather than only credential exchange.
From an operations perspective, this is a stronger fit for ephemeral compute and automated delivery than for long-lived service accounts. IAM and STS controls become the governance layer for who can mint tokens, while condition keys help constrain audience, signing algorithm, and duration. That means security policy can be pushed upstream into AWS, but it also raises the bar for policy design and change management.
For platform and security teams, the practical question is not just whether the feature works, but where it belongs in the identity architecture. It can reduce secret sprawl and improve credential hygiene, yet it adds dependency on token verification logic in every external integration path. Teams will need to standardize token handling, audit claim usage, and test failure modes around expired tokens, mismatched audiences, and trust drift.
With IAM outbound identity federation, you exchange your AWS IAM credentials for short-lived JWTs. This mitigates the security risks associated with long-term credentials while enabling consistent authentication patterns. Letโs walk through a scenario where your application running on AWS needs to interact with an external service. To access the external serviceโs APIs or resources, your application calls the AWS Security Token Service (AWS STS) `GetWebIdentityToken` API to obtain a JWT. The following diagram shows this flow:
- Your application running on AWS requests a token from AWS STS by calling the
GetWebIdentityTokenAPI. The application uses its existing AWS credentials obtained from the underlying platform (such as Amazon EC2 instance profiles, AWS Lambda execution roles, or other AWS compute services) to authenticate this API call. - AWS STS returns a cryptographically signed JSON Web Token (JWT) that asserts the identity of your application.
- Your application sends the JWT to the external service for authentication.
- The external service fetches the verification keys from the JSON Web Key Set (JWKS) endpoint to verify the tokenโs authenticity.
- The external service validates the JWTโs signature using these verification keys and confirms the token is authentic and was issued by AWS.
- After successful verification, the external service exchanges the JWT for its own credentials. Your application can then use these credentials to perform its intended operations.
To begin using this feature, I need to enable outbound identity federation for my AWS account. I navigate to IAM and choose Account settings under Access management in the left-hand navigation pane.
After I enable the feature, AWS generates a unique issuer URL for my AWS account that hosts the OpenID Connect (OIDC) discovery endpoints at /.well-known/openid-configuration and /.well-known/jwks.json. The OpenID Connect (OIDC) discovery endpoints contain the keys and metadata necessary for token verification.
Next, I need to configure IAM permissions. My IAM principal (role or user) must have the sts:GetWebIdentityToken permission to request tokens.
For example, the following identity policy specifies access to the STS GetWebIdentityToken API, enabling the IAM principal to generate tokens.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:GetWebIdentityToken",
"Resource": "*",
}
]
}
At this stage, I need to configure the external service to trust and accept tokens issued by my AWS account. The specific steps vary by service, but generally involve:
- Registering my AWS account issuer URL as a trusted identity provider
- Configuring which claims to validate (audience, subject patterns)
- Mapping token claims to permissions in the external service
Now, let me walk you through an example showing both the client-side token generation and server-side verification process. First, I call the STS
GetWebIdentityToken API to obtain a JWT that asserts my AWS identity. When calling the API, I can specify the intended audience, signing algorithm, and token lifetime as request parameters.
Audience: Populates the `aud` claim in the JWT, identifying the intended recipient of the token (for example, โmy-appโ)DurationSeconds: The token lifetime in seconds, ranging from 60 seconds (1 minute) to 3600 seconds (1 hour), with a default of 300 seconds (5 minutes)SigningAlgorithm: Choose either ES384 (ECDSA using P-384 and SHA-384) or RS256 (RSA using SHA-256)Tags(optional): An array of key-value pairs that appear as custom claims in the token, which you can use to include additional context that enables external services to implement fine-grained access control
import boto3
sts_client = boto3.client('sts')
response = sts_client.get_web_identity_token(
Audience=['my-app'],
SigningAlgorithm='ES384', # or 'RS256'
DurationSeconds=300
)
jwt_token = response['WebIdentityToken']
print(jwt_token)
This returns a signed JWT that I can inspect using any JWT parser.
{
eyJraWQiOiJFQzM4NF8wIiwidHlwIjoiSldUIiwiYWxnIjoiRVMzODQifQ.hey<REDACTED FOR BREVITY>...
I can decode the token using any JWT parser like this JWT Debugger. The token header shows itโs signed with ES384 (ECDSA).
{
"kid": "EC384_0",
"typ": "JWT",
"alg": "ES384"
}
Also, the payload contains standard OIDC claims plus AWS specific metadata. The standard OIDC claims include subject (โsubโ), audience (โaudโ), issuer (โissโ), and others.
{
"aud": "my-app",
"sub": "arn:aws:iam::ACCOUNT_ID:role/MyAppRole",
"https://sts.amazonaws.com/": {
"aws_account": "ACCOUNT_ID",
"source_region": "us-east-1",
"principal_id": "arn:aws:iam::ACCOUNT_ID:role/MyAppRole"
},
"iss": "https://abc12345-def4-5678-90ab-cdef12345678.tokens.sts.global.api.aws",
"exp": 1759786941,
"iat": 1759786041,
"jti": "5488e298-0a47-4c5b-80d7-6b4ab8a4cede"
}
AWS STS also enriches the token with identity-specific claims (such as account ID, organization ID, and principal tags) and session context. These claims provide information about the compute environment and session where the token request originated. AWS STS automatically includes these claims when applicable based on the requesting principalโs session context. You can also add custom claims to the token by passing request tags to the API call. To learn more about claims provided in the JWT, visit the documentation page.
Note the iss (issuer) claim. This is your account-specific issuer URL that external services use to verify that the token originated from a trusted AWS account. External services can verify the JWT by validating its signature using AWSโs verification keys available at a public JSON Web Key Set (JWKS) endpoint hosted at the /.well-known/jwks.json endpoint of the issuer URL.
Now, letโs look at how external services handle this identity token.
Hereโs a snippet of Python example that external services can use to verify AWS tokens:
import json
import jwt
import requests
from jwt import PyJWKClient
# Trusted issuers list - obtained from EnableOutboundFederation API response
TRUSTED_ISSUERS = [
"https://EXAMPLE.tokens.sts.global.api.aws",
# Add your trusted AWS account issuer URLs here
# Obtained from EnableOutboundFederation API response
]
def verify_aws_jwt(token, expected_audience=None):
"""Verify an AWS IAM outbound identity federation JWT"""
try:
# Get issuer from token
unverified_payload = jwt.decode(token, options={"verify_signature": False})
issuer = unverified_payload.get('iss')
# Verify issuer is trusted
if not TRUSTED_ISSUERS or issuer not in TRUSTED_ISSUERS:
raise ValueError(f"Untrusted issuer: {issuer}")
# Fetch JWKS from AWS using PyJWKClient
jwks_client = PyJWKClient(f"{issuer}/.well-known/jwks.json")
signing_key = jwks_client.get_signing_key_from_jwt(token)
# Verify token signature and claims
decoded_token = jwt.decode(
token,
signing_key.key,
algorithms=["ES384", "RS256"],
audience=expected_audience,
issuer=issuer
)
return decoded_token
except Exception as e:
print(f"Token verification failed: {e}")
return None
Using IAM policies to control access to token generationAn IAM principal (such as a role or user) must have the
sts:GetWebIdentityToken permission in their IAM policies to request tokens for authentication with external services. AWS account administrators can configure this permission in all relevant AWS policy types such as identity policies, service control policies (SCPs), resource control policies (RCPs), and virtual private cloud endpoint (VPCE) policies to control which IAM principals in their account can generate tokens.
Additionally, administrators can use the new condition keys to specify signing algorithms (sts:SigningAlgorithm), permitted token audiences (sts:IdentityTokenAudience), and maximum token lifetimes (sts:DurationSeconds). To learn more about the condition keys, visit IAM and STS Condition keys documentation page.
Additional things to knowHere are key details about this launch:
- Availability โ AWS IAM outbound identity federation is available at no additional cost in all AWS commercial Regions, AWS GovCloud (US) Regions, and China Regions.
- Pricing โ This feature is available at no additional cost.
โ Donnie Editors note: 11/22/25- Getting Started documentation added
Enjoyed this article? Sign up for our newsletter to receive regular insights and stay connected.
