@ttoss/cloud-auth
AWS Cognito authentication infrastructure as code. Creates user pools, identity pools, and Lambda triggers with CloudFormation.
Installation
pnpm add @ttoss/cloud-auth
Quick Start
// src/cloudformation.ts
import { createAuthTemplate } from '@ttoss/cloud-auth';
export default createAuthTemplate();
Core Features
User Pool Configuration
The template creates a secure user pool with email-based authentication by default:
const template = createAuthTemplate({
autoVerifiedAttributes: ['email'], // Default
usernameAttributes: ['email'], // Default
deletionProtection: 'ACTIVE', // Optional: ACTIVE | INACTIVE
schema: [
{
attributeDataType: 'String',
name: 'department',
required: false,
mutable: true,
stringAttributeConstraints: {
maxLength: '100',
minLength: '1',
},
},
],
});
Lambda Triggers
Customize authentication workflows with AWS Cognito Lambda triggers. Lambda triggers accept either string ARNs or Fn::GetAtt
CloudFormation references.
Basic Lambda Trigger Setup
const template = createAuthTemplate({
lambdaTriggers: {
preSignUp: 'arn:aws:lambda:us-east-1:123456789:function:PreSignUp',
postConfirmation: { 'Fn::GetAtt': ['PostConfirmationFunction', 'Arn'] },
preTokenGeneration: { 'Fn::GetAtt': ['TokenCustomizerFunction', 'Arn'] },
},
});
Complete Lambda Integration Example
Based on the Terezinha Farm implementation, here's how to integrate Lambda functions with your auth template:
// src/cloudformation.ts
import { createAuthTemplate } from '@ttoss/cloud-auth';
export default () => {
const template = createAuthTemplate({
lambdaTriggers: {
postConfirmation: {
'Fn::GetAtt': ['PostConfirmationLambdaFunction', 'Arn'],
},
},
});
// Add Lambda S3 parameters for Carlin deployment
template.Parameters = {
...template.Parameters,
LambdaS3Bucket: { Type: 'String' },
LambdaS3Key: { Type: 'String' },
LambdaS3ObjectVersion: { Type: 'String' },
};
// Define Lambda function resource
template.Resources = {
...template.Resources,
PostConfirmationLambdaFunction: {
Type: 'AWS::Lambda::Function',
Properties: {
Handler: 'triggers.postConfirmation',
Code: {
S3Bucket: { Ref: 'LambdaS3Bucket' },
S3Key: { Ref: 'LambdaS3Key' },
S3ObjectVersion: { Ref: 'LambdaS3ObjectVersion' },
},
Role: 'arn:aws:iam::account:role/lambda-execution-role',
Runtime: 'nodejs22.x',
},
},
};
return template;
};
Lambda Function Implementation
Create your trigger functions following AWS Lambda handler patterns:
// src/triggers.ts
import type { PostConfirmationTriggerHandler } from 'aws-lambda';
export const postConfirmation: PostConfirmationTriggerHandler = async (
event
) => {
const email = event.request.userAttributes.email;
// Custom logic: send welcome email, create user profile, etc.
console.log(`New user confirmed: ${email}`);
// Always return the event object
return event;
};
Available Lambda Triggers
Check Customizing user pool workflows with Lambda triggers for more information.
Authentication Flow:
preSignUp
- Validate signup data, auto-confirm userspostConfirmation
- Execute post-signup actionspreAuthentication
- Custom authentication validationpostAuthentication
- Track logins, update last seen
Token Customization:
preTokenGeneration
- Add custom claims, modify token content
User Migration:
userMigration
- Migrate users from external systems
Custom Challenges:
defineAuthChallenge
- Define custom authentication flowscreateAuthChallenge
- Generate custom challengesverifyAuthChallengeResponse
- Validate challenge responses
Messaging:
customMessage
- Customize email/SMS contentcustomEmailSender
- Third-party email providerscustomSMSSender
- Third-party SMS providers
Deployment with Carlin
When using Carlin deploy, Lambda functions are automatically built and uploaded to S3. Your Handler
property should match your file structure:
src/
└── triggers.ts # Handler: 'triggers.postConfirmation's
The S3 parameters (LambdaS3Bucket
, LambdaS3Key
, LambdaS3ObjectVersion
) are automatically injected by Carlin and referenced in your Lambda function's Code
property.
Identity Pool
Enable federated identities for AWS resource access:
const template = createAuthTemplate({
identityPool: {
enabled: true,
name: 'MyApp_IdentityPool',
allowUnauthenticatedIdentities: false,
},
});
Custom IAM Policies
Define specific permissions for authenticated and unauthenticated users:
const template = createAuthTemplate({
identityPool: {
enabled: true,
authenticatedPolicies: [
{
PolicyName: 'S3Access',
PolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['s3:GetObject', 's3:PutObject'],
Resource: 'arn:aws:s3:::my-bucket/${aws:PrincipalTag/userId}/*',
},
],
},
},
],
},
});
Principal Tags for Access Control
Enable attribute-based access control using JWT claims as IAM principal tags:
// Default principal tags
const template = createAuthTemplate({
identityPool: { enabled: true },
// Maps: appClientId → 'aud', userId → 'sub'
});
// Custom principal tags
const template = createAuthTemplate({
identityPool: {
enabled: true,
principalTags: {
department: 'custom:department',
role: 'custom:role',
userId: 'sub',
},
},
});
Use principal tags in IAM policies for fine-grained access control:
{
"Effect": "Allow",
"Action": "dynamodb:Query",
"Resource": "arn:aws:dynamodb:*:*:table/UserData",
"Condition": {
"StringEquals": {
"dynamodb:LeadingKeys": "${aws:PrincipalTag/userId}"
}
}
}
External IAM Roles
Use existing IAM roles instead of creating new ones:
const template = createAuthTemplate({
identityPool: {
enabled: true,
authenticatedRoleArn: 'arn:aws:iam::123456789012:role/AuthenticatedRole',
unauthenticatedRoleArn:
'arn:aws:iam::123456789012:role:UnauthenticatedRole',
},
});
Template Outputs
The template provides these CloudFormation outputs for integration:
- Region: AWS region for Amplify Auth configuration
- UserPoolId: Cognito User Pool ID
- AppClientId: User Pool Client ID for applications
- IdentityPoolId: Identity Pool ID (when enabled)
Access outputs in other CloudFormation templates:
AuthConfig:
UserPoolId: !ImportValue MyAuthStack:UserPoolId
AppClientId: !ImportValue MyAuthStack:AppClientId
Advanced Configuration
Custom User Attributes
Define application-specific user attributes with validation:
const template = createAuthTemplate({
schema: [
{
attributeDataType: 'Number',
name: 'employee_id',
required: true,
mutable: false,
numberAttributeConstraints: {
minValue: '1000',
maxValue: '99999',
},
},
{
attributeDataType: 'String',
name: 'department',
required: false,
mutable: true,
stringAttributeConstraints: {
minLength: '2',
maxLength: '50',
},
},
],
});
Production Considerations
For production deployments:
- Use
Fn::GetAtt
references instead of hardcoded ARNs for Lambda functions - Enable deletion protection (
deletionProtection: 'ACTIVE'
) for production user pools - Configure appropriate IAM roles with minimal required permissions for Lambda functions
- Implement proper error handling in Lambda triggers to prevent authentication failures
- Set up monitoring and alerting for authentication metrics
- Consider regional failover strategies