AWS Cognito Infrastructure Setup
This guide walks you through setting up AWS Cognito infrastructure manually using the AWS Console. You’ll create a User Pool, configure App Clients for different authentication flows, create users, and set up user groups.
Prerequisites
Before starting, ensure you have:
An active AWS account
Appropriate IAM permissions to create and manage Cognito resources
Access to the AWS Management Console
Step 1: Create a User Pool
Navigate to Amazon Cognito
Open the AWS Management Console
Search for “Cognito” and select “Amazon Cognito”
Click “Create user pool”
Configure Sign-in Experience
Authentication providers: Select “Cognito user pool”
Cognito user pool sign-in options: Choose your preferred options: - Email (recommended for most applications) - Username (optional, based on your needs) - Phone number (optional, requires SMS configuration)
Click “Next”
Configure Security Requirements
Password policy: Choose between “Cognito defaults” or “Custom”
For custom policy, recommended settings: - Minimum length: 8 characters - Require numbers - Require special characters - Require uppercase letters - Require lowercase letters
Multi-factor authentication: - Optional (recommended for production) - Required (for high-security applications)
User account recovery: Select preferred options: - Email only (most common) - SMS and email (if phone numbers are collected)
Click “Next”
Configure Sign-up Experience
Self-service sign-up: Enable if you want users to self-register
Cognito-assisted verification: Choose verification methods: - Send email verification (recommended) - Send SMS verification (if using phone numbers)
Required attributes: Select attributes to collect during sign-up: - email (strongly recommended) - given_name (optional) - family_name (optional) - preferred_username (optional)
Custom attributes: Add any application-specific attributes
Click “Next”
Configure Message Delivery
Email provider: - Send email with Cognito (for testing/development) - Send email with Amazon SES (recommended for production)
SMS: Configure if using SMS verification
Click “Next”
Integrate Your App
User pool name: Enter a descriptive name (e.g., “MyApp-UserPool”)
Hosted authentication pages: - Check “Use the Cognito Hosted UI” if you want AWS-hosted login pages - Leave unchecked if you’re building custom authentication UI
Initial app client: We’ll configure this in the next step - App client name: Enter a temporary name (we’ll create proper clients later) - Client secret: Select “Don’t generate a client secret” for now
Click “Next”
Review and Create
Review all settings
Click “Create user pool”
Save the User Pool ID - you’ll need this for configuration
Step 2: Create App Clients
You’ll need two different app clients for different authentication flows:
App Client 1: Client Credentials Flow
This client is used for server-to-server authentication.
Navigate to App Integration
In your User Pool, go to the “App integration” tab
Click “Create app client”
Configure App Client
App type: Select “Confidential client”
App client name: “MyApp-ClientCredentials”
Client secret: “Generate a client secret”
Allowed callback URLs: Not needed for client credentials
Allowed sign-out URLs: Not needed for client credentials
Authentication Flows
Uncheck “ALLOW_USER_SRP_AUTH”
Uncheck “ALLOW_USER_PASSWORD_AUTH”
Uncheck “ALLOW_REFRESH_TOKEN_AUTH”
Check “ALLOW_ADMIN_USER_PASSWORD_AUTH” (for admin operations)
Check “ALLOW_CUSTOM_AUTH” (optional)
OAuth 2.0 Settings
Allowed OAuth flows: - Client credentials
Allowed OAuth scopes: Select appropriate scopes for your API
Hosted UI settings: Not needed for client credentials
Save the Configuration
Click “Create app client”
Save the Client ID and Client Secret - you’ll need these for configuration
App Client 2: User Password Flow
This client is used for user authentication with username/password.
Create Another App Client
Click “Create app client” again
Configure App Client
App type: Select “Public client” or “Confidential client” based on your needs
App client name: “MyApp-UserAuth”
Client secret: - Don’t generate for public clients (mobile/SPA) - Generate for confidential clients (server-side web apps)
Authentication Flows
Check “ALLOW_USER_PASSWORD_AUTH”
Check “ALLOW_REFRESH_TOKEN_AUTH”
Uncheck “ALLOW_USER_SRP_AUTH” (unless you need SRP)
Uncheck “ALLOW_ADMIN_USER_PASSWORD_AUTH”
OAuth 2.0 Settings
Allowed OAuth flows: - Authorization code grant - Implicit grant (only if needed for legacy apps)
Allowed OAuth scopes: - email - openid - profile
Callback URLs: Add your application’s callback URLs
Sign-out URLs: Add your application’s sign-out URLs
Advanced Settings
Access token expiration: 60 minutes (default, adjust as needed)
ID token expiration: 60 minutes (default, adjust as needed)
Refresh token expiration: 30 days (default, adjust as needed)
Save the Configuration
Click “Create app client”
Save the Client ID (and Client Secret if generated)
Step 3: Create User Groups
User groups are essential for authorization and role-based access control.
Navigate to Users and Groups
In your User Pool, go to “Users and groups”
Click on the “Groups” tab
Click “Create group”
Create Admin Group
Group name: “admin”
Description: “Administrator group with full access”
IAM role: Leave blank unless you need AWS resource access
Precedence: 1 (lower numbers have higher precedence)
Click “Create group”
Create User Group
Click “Create group” again
Group name: “user”
Description: “Standard user group”
IAM role: Leave blank
Precedence: 10
Click “Create group”
Create Additional Groups (Optional)
Create any additional groups your application needs: - “moderator” (precedence: 5) - “readonly” (precedence: 15) - “premium” (precedence: 8)
Step 4: Create Users
Create test users to verify your setup.
Create Admin User
Go to “Users and groups” → “Users” tab
Click “Create user”
Username: “admin@example.com”
Email: “admin@example.com”
Temporary password: Generate a secure password
Check “Send an invitation to this new user?”
Check “Mark phone number as verified” (if applicable)
Check “Mark email as verified”
Click “Create user”
Create Regular User
Click “Create user” again
Username: “user@example.com”
Email: “user@example.com”
Temporary password: Generate a secure password
Check “Send an invitation to this new user?”
Check “Mark email as verified”
Click “Create user”
Step 5: Assign Users to Groups
Assign Admin User to Admin Group
Go to “Users and groups” → “Users” tab
Click on the admin user
Click “Add to group”
Select “admin” group
Click “Add to group”
Assign Regular User to User Group
Click on the regular user
Click “Add to group”
Select “user” group
Click “Add to group”
Step 6: Configure User Pool Settings
Advanced Configuration
App Client Settings (if using Hosted UI)
Go to “App integration” → “App client settings”
Configure each app client: - Enabled Identity Providers: Cognito User Pool - Callback URL(s): Your application’s callback URLs - Sign out URL(s): Your application’s logout URLs - Allowed OAuth Flows: Based on your app client type - Allowed OAuth Scopes: email, openid, profile
Domain Name (if using Hosted UI)
Go to “App integration” → “Domain name”
Choose either: - Amazon Cognito domain: Use cognito subdomain - Your own domain: Use custom domain (requires SSL certificate)
Triggers (Optional)
Go to “General settings” → “Triggers”
Configure Lambda triggers for: - Pre sign-up validation - Post confirmation actions - Pre authentication validation - Post authentication actions - User migration
Step 7: Testing Your Setup
Using Bruno/API Testing
You can test your Cognito setup using the Bruno API client (as shown in your test files):
Test User Authentication:
POST https://cognito-idp.{region}.amazonaws.com/ Content-Type: application/x-amz-json-1.1 X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth { "AuthParameters": { "USERNAME": "user@example.com", "PASSWORD": "user_password" }, "AuthFlow": "USER_PASSWORD_AUTH", "ClientId": "{your_user_auth_client_id}" }
Test Client Credentials:
POST https://cognito-idp.{region}.amazonaws.com/ Content-Type: application/x-amz-json-1.1 X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth { "AuthParameters": { "SECRET_HASH": "{calculated_secret_hash}" }, "AuthFlow": "CLIENT_CREDENTIALS", "ClientId": "{your_client_credentials_client_id}" }
Configuration Summary
After completing these steps, you’ll have:
User Pool Information:
User Pool ID: us-east-1_XXXXXXXXX
User Pool Region: us-east-1
User Pool Domain: https://your-domain.auth.us-east-1.amazoncognito.com
App Clients:
Client Credentials App:
Client ID: xxxxxxxxxxxxxxxxxxxx
Client Secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Allowed Flows: ALLOW_ADMIN_USER_PASSWORD_AUTH
User Authentication App:
Client ID: yyyyyyyyyyyyyyyyyyyy
Client Secret: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
Allowed Flows: ALLOW_USER_PASSWORD_AUTH, ALLOW_REFRESH_TOKEN_AUTH
Groups Created:
admin (precedence: 1)
user (precedence: 10)
Test Users:
admin@example.com (member of admin group)
user@example.com (member of user group)
Use these values to configure your auth-middleware as described in the AWS Cognito Provider documentation.
Troubleshooting
Common Issues
Authentication Fails
Verify the User Pool ID and region are correct
Check that the app client has the correct authentication flows enabled
Ensure users are confirmed (check email verification)
Group Information Not Available
Verify users are assigned to groups
Check that the groups were created successfully
Ensure your JWT tokens include group information
Client Secret Issues
For public clients (mobile/SPA), don’t use client secrets
For confidential clients, ensure the secret is correctly configured
Verify the secret hasn’t been regenerated
Token Expiration Issues
Check token expiration settings in app client configuration
Implement proper token refresh logic in your application
Consider adjusting token lifetimes based on security requirements
Security Best Practices
Production Considerations
Use custom domains for Hosted UI
Enable MFA for all users
Implement proper token refresh mechanisms
Use short-lived access tokens (15-60 minutes)
Configure appropriate CORS settings
Monitoring and Logging
Enable CloudTrail for Cognito API calls
Set up CloudWatch alarms for failed authentication attempts
Monitor user pool metrics
Implement application-level audit logging
Backup and Recovery
Export user data regularly
Document your configuration
Test user pool recovery procedures
Keep app client secrets secure
Step 8: Create Identity Pool (Optional)
Identity Pools allow your users to obtain temporary AWS credentials to access AWS services (S3, DynamoDB, etc.) after authenticating through your User Pool.
Create Identity Pool
Navigate to Identity Pools
In the AWS Console, go to Amazon Cognito
Click “Federated Identities” (or “Identity pools” in newer console)
Click “Create identity pool”
Configure Identity Pool
Identity pool name: “MyAppIdentityPool”
Enable access to unauthenticated identities: Uncheck (unless needed)
Click “Create pool”
Configure Authentication Providers
Authentication providers tab
Select “Cognito” tab
Add your User Pool: - User Pool ID: us-east-1_XXXXXXXXX (from Step 1) - App client ID: Use your User Authentication app client ID
Click “Save changes”
Create IAM Roles
The console will prompt you to create IAM roles:
Authenticated role (for logged-in users):
Role name: “Cognito_MyAppIdentityPoolAuth_Role”
Trusted entities: Cognito Identity Pool
Permissions: Add policies based on your needs:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject" ], "Resource": "arn:aws:s3:::my-bucket/users/${cognito-identity.amazonaws.com:sub}/*" }, { "Effect": "Allow", "Action": [ "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem" ], "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/MyTable", "Condition": { "ForAllValues:StringEquals": { "dynamodb:LeadingKeys": ["${cognito-identity.amazonaws.com:sub}"] } } } ] }
Unauthenticated role (if enabled):
Role name: “Cognito_MyAppIdentityPoolUnauth_Role”
Permissions: Very restricted access or none
Save Identity Pool Configuration
Click “Allow” to create the IAM roles
Save the Identity Pool ID - you’ll need this for configuration
Configure Enhanced Flow
For better security, use the enhanced (simplified) authflow:
Edit Identity Pool
Go to your Identity Pool settings
Click “Edit identity pool”
Check “Use enhanced flow”
Save changes
Trust Relationships
Verify the authenticated role has the correct trust relationship:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "cognito-identity.amazonaws.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "cognito-identity.amazonaws.com:aud": "us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }, "ForAnyValue:StringLike": { "cognito-identity.amazonaws.com:amr": "authenticated" } } } ] }
Test Identity Pool with AWS CLI
Get ID Token from User Pool (from Step 7):
# Save the idToken from authentication response ID_TOKEN="eyJraWQ..."
Get Identity ID:
aws cognito-identity get-id \ --identity-pool-id "us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \ --logins "cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXXXX=$ID_TOKEN" \ --region us-east-1
Response:
{ "IdentityId": "us-east-1:yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" }
Get AWS Credentials:
aws cognito-identity get-credentials-for-identity \ --identity-id "us-east-1:yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" \ --logins "cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXXXX=$ID_TOKEN" \ --region us-east-1
Response:
{ "IdentityId": "us-east-1:yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy", "Credentials": { "AccessKeyId": "ASIA...", "SecretKey": "...", "SessionToken": "...", "Expiration": 1735574400.0 } }
Use AWS Credentials:
# Export credentials export AWS_ACCESS_KEY_ID="ASIA..." export AWS_SECRET_ACCESS_KEY="..." export AWS_SESSION_TOKEN="..." # Test access to S3 aws s3 ls s3://my-bucket/users/
Test Identity Pool with Bruno
Request 1: Get Identity ID
POST https://cognito-identity.us-east-1.amazonaws.com/ Content-Type: application/x-amz-json-1.1 X-Amz-Target: AWSCognitoIdentityService.GetId { "IdentityPoolId": "us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "Logins": { "cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXXXX": "{{idToken}}" } }Save the IdentityId from the response.
Request 2: Get AWS Credentials
POST https://cognito-identity.us-east-1.amazonaws.com/ Content-Type: application/x-amz-json-1.1 X-Amz-Target: AWSCognitoIdentityService.GetCredentialsForIdentity { "IdentityId": "{{identityId}}", "Logins": { "cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXXXX": "{{idToken}}" } }Response contains temporary AWS credentials.
Configure auth-middleware Identity Pool Provider
If you’re using the identity pool provider in auth-middleware:
from auth_middleware.providers.authn.cognito_authz_provider_settings import (
CognitoAuthzProviderSettings
)
from auth_middleware.providers.authn.cognito_provider import CognitoProvider
settings = CognitoAuthzProviderSettings(
# User Pool settings
user_pool_id="us-east-1_XXXXXXXXX",
user_pool_region="us-east-1",
user_pool_client_id="your-client-id",
# Identity Pool settings (optional)
identity_pool_id="us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
identity_pool_region="us-east-1",
)
provider = CognitoProvider(settings=settings)
Then in your application, you can obtain AWS credentials:
from fastapi import Request, Depends
from auth_middleware.functions import require_user
@app.get("/aws-credentials")
async def get_aws_credentials(
request: Request,
_: None = Depends(require_user())
):
user = request.state.current_user
# Get AWS credentials for the authenticated user
# This would use the provider's identity pool integration
credentials = await provider.get_aws_credentials(user.id_token)
return {
"access_key_id": credentials.access_key_id,
"secret_access_key": credentials.secret_access_key,
"session_token": credentials.session_token,
"expiration": credentials.expiration,
}
Identity Pool Configuration Summary
After completing Identity Pool setup:
Identity Pool ID: us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Identity Pool Region: us-east-1
Authentication Provider:
Type: Cognito User Pool
User Pool ID: us-east-1_XXXXXXXXX
App Client ID: yyyyyyyyyyyyyyyyyyyy
IAM Roles:
Authenticated Role: Cognito_MyAppIdentityPoolAuth_Role
Authenticated Role ARN: arn:aws:iam::123456789012:role/Cognito_MyAppIdentityPoolAuth_Role
Identity Pool Best Practices
Principle of Least Privilege
Grant only necessary permissions in IAM roles
Use resource-level permissions with user context
Leverage condition keys like
${cognito-identity.amazonaws.com:sub}
Use Enhanced Flow
Always enable enhanced (simplified) authflow
More secure than classic flow
Better integration with modern SDKs
Credential Caching
Cache AWS credentials until expiration
Refresh before expiration (e.g., at 80% of lifetime)
Don’t request new credentials for every API call
Resource Isolation
Use Cognito identity ID in resource paths
Example S3 path:
s3://bucket/users/${cognito-identity.amazonaws.com:sub}/Example DynamoDB key: Use identity ID as partition key
Monitoring
Monitor IAM role usage in CloudTrail
Set up alarms for unauthorized access attempts
Track credential request patterns
Next Steps
Now that your Cognito infrastructure is set up:
Configure the auth-middleware with your Cognito settings
Implement the authentication flow in your application
Set up authorization rules based on user groups
Test the complete authentication and authorization flow
(Optional) Implement Identity Pool integration for AWS resource access
Deploy to production with appropriate security settings
For implementation details, see the AWS Cognito Provider documentation.