Skip to main content
Instead of storing long-lived AWS credentials as Vercel environment variables, you can use OpenID Connect (OIDC) federation. Vercel presents a short-lived identity token, AWS validates it, and issues temporary credentials automatically.

Why use OIDC

Stored credentialsOIDC
Long-lived keys that never expireTokens expire automatically (~1 hour)
Must be rotated manuallyRotation is automatic
Key ID visible in CloudTrailCloudTrail shows exactly which Vercel deployment assumed the role
Can be used from anywhere if leakedRole can only be assumed by your specific Vercel project

Prerequisites

  • Vercel Team ID (team_xxxxx) — found in Vercel → Account → Settings
  • Vercel Project ID (prj_xxxxx) — found in Project → Settings → General
  • AWS CLI configured locally (only needed for the one-time stack deployment)

Setup

1

Get your Vercel IDs

Team ID
  1. Go to vercel.com/account
  2. Click on your team name → Settings
  3. Copy the Team ID (format: team_xxxxx)
Project ID
  1. Open your Vercel project
  2. Navigate to Settings → General
  3. Copy the Project ID (format: prj_xxxxx)
2

Deploy the CloudFormation stack

This one-time command creates an OIDC provider and IAM role in your AWS account.
# Set your Vercel IDs
VERCEL_TEAM_ID="team_xxxxx"
VERCEL_PROJECT_ID="prj_xxxxx"

# Deploy the stack
aws cloudformation create-stack \
  --stack-name wraps-vercel-oidc \
  --template-body file://cloudformation/vercel-oidc-role.yaml \
  --parameters \
    ParameterKey=VercelTeamId,ParameterValue=${VERCEL_TEAM_ID} \
    ParameterKey=VercelProjectId,ParameterValue=${VERCEL_PROJECT_ID} \
  --capabilities CAPABILITY_NAMED_IAM \
  --region us-east-1

# Wait for the stack to finish
aws cloudformation wait stack-create-complete \
  --stack-name wraps-vercel-oidc \
  --region us-east-1
3

Get the Role ARN

aws cloudformation describe-stacks \
  --stack-name wraps-vercel-oidc \
  --region us-east-1 \
  --query 'Stacks[0].Outputs[?OutputKey==`BackendRoleArn`].OutputValue' \
  --output text
The output looks like:
arn:aws:iam::123456789012:role/wraps-vercel-backend-role
Copy this value — you’ll need it in the next step.
4

Configure Vercel environment variables

Go to your Vercel project → Settings → Environment Variables and add:
VariableValue
AWS_REGIONus-east-1 (or your deployment region)
AWS_ROLE_ARNThe ARN from the previous step
Vercel automatically sets AWS_WEB_IDENTITY_TOKEN_FILE. Do not set this manually — it will break the OIDC flow.
5

Remove old credentials

Delete these variables from Vercel if they exist:
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_PROFILE (only needed for local dev)
Leaving old credentials in place will cause the SDK to use them instead of OIDC, defeating the purpose of this setup.
6

Redeploy on Vercel

Trigger a new deployment to pick up the new environment variables:
vercel --prod
Or push a commit to your production branch.

How it works

Vercel Deployment

Next.js API route calls WrapsEmail.send()

AWS SDK reads AWS_ROLE_ARN env var

AWS SDK reads AWS_WEB_IDENTITY_TOKEN_FILE (set automatically by Vercel)

Call STS AssumeRoleWithWebIdentity

Vercel OIDC Provider validates the token

Trust policy conditions checked:
  - aud = "vercel"
  - sub = "team:xxx:project:xxx:environment:production"

Temporary credentials returned (valid ~1 hour)

Wraps uses credentials to call SES
In your application code, pass the role ARN:
import { WrapsEmail } from '@wraps.dev/email';

// Picks up AWS_ROLE_ARN and the OIDC token automatically
const email = new WrapsEmail({
  roleArn: process.env.AWS_ROLE_ARN,
});

Local development

OIDC only works inside Vercel deployments. For local development, continue using a named AWS profile:
# .env.local
AWS_PROFILE=default
The SDK automatically falls back to the standard credential chain when AWS_ROLE_ARN is not set.

Verification

After redeploying, verify that OIDC is working:
  1. Check Vercel build logs — look for a successful deployment with no AWS credential errors
  2. Check CloudTrail (optional):
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity \
  --region us-east-1 \
  --max-items 5

Troubleshooting

Cause: The trust policy conditions don’t match your Vercel team or project.Fix: Check the CloudFormation parameters are correct:
aws cloudformation describe-stacks \
  --stack-name wraps-vercel-oidc \
  --region us-east-1 \
  --query 'Stacks[0].Parameters'
If the Team ID or Project ID is wrong, delete the stack and redeploy with the correct values.
Cause: Vercel isn’t providing the OIDC token, usually because AWS_ROLE_ARN is missing.Fix:
  1. Confirm AWS_ROLE_ARN is set in Vercel environment variables
  2. Confirm AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY have been removed
  3. Redeploy the project
Cause: The AWS SDK can’t find any usable credentials.Fix:
  1. Check that both AWS_REGION and AWS_ROLE_ARN are set in Vercel
  2. Verify the CloudFormation stack completed successfully:
    aws cloudformation describe-stacks \
      --stack-name wraps-vercel-oidc \
      --region us-east-1 \
      --query 'Stacks[0].StackStatus'
    
  3. Confirm the OIDC provider exists:
    aws iam list-open-id-connect-providers
    

Security properties

  • Environment-specific — the trust policy only allows production Vercel deployments
  • Project-specific — only your exact Vercel project can assume the role
  • Least privilege — the role only has sts:AssumeRole permission
  • Short-lived — tokens expire after approximately 1 hour
  • Auditable — every assumption is logged in AWS CloudTrail

Cleanup

To remove the OIDC setup:
aws cloudformation delete-stack \
  --stack-name wraps-vercel-oidc \
  --region us-east-1

Build docs developers (and LLMs) love