@lafken/auth
Define and manage Amazon Cognito User Pools using TypeScript decorators. @lafken/auth lets you configure authentication flows, password policies, user attributes, MFA, identity providers, and Lambda triggers — all from a single resolver configuration.
Installation
npm install @lafken/authGetting Started
Configure AuthResolver with your User Pool settings, define attributes with @Attributes, and add Lambda triggers with @AuthExtension:
import { createApp } from '@lafken/main';
import { AuthResolver } from '@lafken/auth/resolver';
import { Attributes, Standard, Custom } from '@lafken/auth/main';
import { AuthExtension, Trigger, Event } from '@lafken/auth/main';
// 1. Define user attributes
@Attributes()
export class UserAttributes {
@Standard({ required: true })
email: string;
@Standard({ required: false })
phoneNumber: string;
@Custom({ minLen: 2, maxLen: 50 })
displayName: string;
}
// 2. Define Lambda triggers
@AuthExtension()
export class AuthTriggers {
@Trigger({ type: 'preSignUp' })
validateSignUp(@Event() event: any) {
return event;
}
}
// 3. Register in the app
createApp({
name: 'my-app',
resolvers: [
new AuthResolver({
name: 'app-auth',
userPool: {
attributes: UserAttributes,
selfSignUpEnabled: true,
signInAliases: ['email'],
passwordPolicy: {
minLength: 8,
requireUppercase: true,
requireDigits: true,
},
},
userClient: {
authFlows: ['allow_user_password_auth', 'allow_refresh_token_auth'],
},
extensions: [AuthTriggers],
}),
],
});Features
User Pool
Configure the Cognito User Pool through the userPool option in AuthResolver:
new AuthResolver({
name: 'customer-auth',
userPool: {
selfSignUpEnabled: true,
signInAliases: ['email', 'phone'],
usernameAttributes: ['email'],
autoVerifyAttributes: ['email'],
signInCaseSensitive: false,
cognitoPlan: 'essentials',
},
});User Pool Options
| Option | Type | Description |
|---|---|---|
attributes |
ClassResource |
Class decorated with @Attributes defining user schema |
selfSignUpEnabled |
boolean |
Allow users to sign up without admin intervention |
signInAliases |
SignInAliases[] |
Identifiers for sign-in: 'email', 'phone', 'preferred_username' |
usernameAttributes |
string[] |
Attributes that can be used as the username |
autoVerifyAttributes |
string[] |
Attributes to auto-verify during sign-up ('email', 'phone') |
signInCaseSensitive |
boolean |
Whether sign-in identifiers are case-sensitive |
cognitoPlan |
CognitoPlan |
Pricing plan: 'lite', 'essentials', 'plus' |
passwordPolicy |
PasswordPolicy |
Password strength requirements |
accountRecovery |
AccountRecovery[] |
Recovery methods: 'verified_email', 'verified_phone_number', 'admin_only' |
email |
EmailConfig |
Email sending configuration (Cognito or SES) |
mfa |
Mfa |
Multi-factor authentication settings |
invitationMessage |
InvitationMessage |
Custom message for admin-created users |
userVerification |
UserVerification |
Verification message and method configuration |
identityProviders |
IdentityProvider[] |
External identity providers (Google, Facebook, etc.) |
Password Policy
Control password strength requirements:
userPool: {
passwordPolicy: {
minLength: 12,
requireUppercase: true,
requireLowercase: true,
requireDigits: true,
requireSymbols: true,
validityDays: 90,
},
}| Option | Type | Description |
|---|---|---|
minLength |
number |
Minimum password length |
requireUppercase |
boolean |
Require at least one uppercase letter |
requireLowercase |
boolean |
Require at least one lowercase letter |
requireDigits |
boolean |
Require at least one digit |
requireSymbols |
boolean |
Require at least one special character |
validityDays |
number |
Number of days before password expires |
User Attributes
Define the User Pool schema using a class decorated with @Attributes. Properties use @Standard for built-in Cognito attributes and @Custom for application-specific fields:
import { Attributes, Standard, Custom } from '@lafken/auth/main';
@Attributes()
export class UserAttributes {
@Standard({ required: true })
email: string;
@Standard({ required: false, mutable: true })
nickname: string;
@Custom({ minLen: 2, maxLen: 100 })
displayName: string;
@Custom({ min: 0, max: 999 })
score: number;
@Custom({ mutable: false })
isVerified: boolean;
}Standard Attributes
Predefined Cognito attributes following the OpenID Connect specification. Supported names:
name, familyName, givenName, middleName, nickname, preferredUsername, profile, picture, website, gender, birthdate, zoneInfo, locale, updated_at, address, email, phoneNumber, sub
| Option | Type | Default | Description |
|---|---|---|---|
required |
boolean |
true |
Whether the attribute is required during sign-up |
mutable |
boolean |
true |
Whether the value can be changed after creation |
Custom Attributes
Application-specific fields with type-aware constraints:
| Type | Options | Description |
|---|---|---|
string |
minLen, maxLen |
String length constraints |
number |
min, max |
Numeric range constraints |
boolean |
mutable |
Mutability only |
All custom attributes default to mutable: true.
MFA (Multi-Factor Authentication)
Configure MFA for the User Pool:
userPool: {
mfa: {
status: 'required',
email: {
subject: 'Your verification code',
body: 'Your code is {####}',
},
sms: 'Your verification code is {####}',
opt: true,
},
}| Option | Type | Description |
|---|---|---|
status |
'off' | 'optional' | 'required' |
MFA enforcement level |
email |
{ subject, body } |
Email-based MFA message template |
sms |
string |
SMS-based MFA message template |
opt |
boolean |
Enable TOTP (authenticator app) as an MFA option |
Email Configuration
Configure how Cognito sends verification and notification emails:
// Using the default Cognito email service
userPool: {
email: {
from: 'noreply@example.com',
reply: 'support@example.com',
},
}
// Using Amazon SES
userPool: {
email: {
account: 'ses',
arn: 'arn:aws:ses:us-east-1:123456789:identity/example.com',
from: 'auth@example.com',
configurationSet: 'my-ses-config',
},
}Verification & Invitation Messages
Customize messages sent during user verification and admin-created user invitations:
userPool: {
userVerification: {
email: {
subject: 'Verify your account',
body: 'Click this link to verify: {##Verify##}',
type: 'link',
},
sms: 'Your verification code is {####}',
},
invitationMessage: {
email: {
subject: 'Welcome to our platform',
body: 'Your username is {username} and temporary password is {####}',
},
sms: 'Your username is {username} and password is {####}',
},
}Identity Providers
Configure external identity providers so users can sign in with third-party accounts:
userPool: {
identityProviders: [
{
type: 'google',
clientId: 'google-client-id',
clientSecret: 'google-client-secret',
scopes: ['openid', 'email', 'profile'],
attributes: {
email: 'email',
displayName: 'name',
},
},
],
}{
type: 'facebook',
clientId: 'fb-app-id',
clientSecret: 'fb-app-secret',
scopes: ['public_profile', 'email'],
apiVersion: 'v18.0',
attributes: {
email: 'email',
displayName: 'name',
},
}Apple
{
type: 'apple',
clientId: 'apple-service-id',
scopes: ['email', 'name'],
keyId: 'key-id',
teamId: 'team-id',
privateKeyValue: '-----BEGIN PRIVATE KEY-----...',
attributes: {
email: 'email',
displayName: 'first_name',
},
}Amazon
{
type: 'amazon',
clientId: 'amazon-client-id',
clientSecret: 'amazon-client-secret',
scopes: ['profile'],
attributes: {
email: 'email',
displayName: 'name',
},
}OIDC (OpenID Connect)
{
type: 'oidc',
name: 'my-oidc-provider',
clientId: 'oidc-client-id',
clientSecret: 'oidc-client-secret',
scopes: ['openid', 'email'],
attributesRequestMethod: 'GET',
authorizeUrl: 'https://provider.com/authorize',
tokenUrl: 'https://provider.com/token',
attributesUrl: 'https://provider.com/userinfo',
jwksUri: 'https://provider.com/.well-known/jwks.json',
attributes: {
email: 'email',
},
}Attribute mappings map your @Attributes class properties to the provider's attribute names.
User Pool Client
Configure the Cognito User Pool Client through the userClient option:
new AuthResolver({
name: 'app-auth',
userClient: {
authFlows: ['allow_user_password_auth', 'allow_refresh_token_auth'],
generateSecret: false,
preventUserExistenceErrors: true,
enableTokenRevocation: true,
validity: {
accessToken: { type: 'hours', value: 1 },
idToken: { type: 'hours', value: 1 },
refreshToken: { type: 'days', value: 30 },
authSession: 300,
},
readAttributes: ['email', 'displayName'],
writeAttributes: ['displayName', 'nickname'],
},
});Auth Flows
| Flow | Description |
|---|---|
allow_user_password_auth |
Username and password authentication |
allow_user_srp_auth |
Secure Remote Password authentication |
allow_admin_user_password_auth |
Admin-initiated password authentication |
allow_custom_auth |
Custom authentication flow |
allow_refresh_token_auth |
Token refresh flow |
allow_user_auth |
General user authentication |
OAuth Configuration
userClient: {
oauth: {
flows: ['code'],
scopes: ['openid', 'email', 'profile'],
callbackUrls: ['https://app.example.com/callback'],
logoutUrls: ['https://app.example.com/logout'],
defaultRedirectUri: 'https://app.example.com/callback',
},
}| Option | Type | Description |
|---|---|---|
flows |
OAuthFlow[] |
'code', 'implicit', 'client_credentials' |
scopes |
string[] |
OAuth scopes (e.g. 'openid', 'email', 'profile') |
callbackUrls |
string[] |
Allowed redirect URLs after sign-in |
logoutUrls |
string[] |
Allowed redirect URLs after sign-out |
defaultRedirectUri |
string |
Default redirect URL |
Token Validity
validity: {
authSession: 300,
accessToken: { type: 'minutes', value: 60 },
idToken: { type: 'minutes', value: 60 },
refreshToken: { type: 'days', value: 30 },
}accessToken, idToken, and refreshToken accept either a number (in minutes) or a ValidityUnit object with type ('seconds', 'minutes', 'hours', 'days') and value.
Extensions (Lambda Triggers)
Extend Cognito behavior with Lambda triggers. Define an extension class with @AuthExtension and add @Trigger methods for each lifecycle event:
import { AuthExtension, Trigger, Event } from '@lafken/auth/main';
@AuthExtension()
export class AuthTriggers {
@Trigger({ type: 'preSignUp' })
validateSignUp(@Event() event: any) {
// Auto-confirm or reject users
event.response.autoConfirmUser = true;
return event;
}
@Trigger({ type: 'postConfirmation' })
onConfirmed(@Event() event: any) {
// Create user profile in database
return event;
}
@Trigger({ type: 'customMessage' })
customizeMessage(@Event() event: any) {
// Customize verification emails
return event;
}
}Register extensions in the resolver:
new AuthResolver({
name: 'app-auth',
extensions: [AuthTriggers],
});Available Trigger Types
| Trigger | Description |
|---|---|
preSignUp |
Validate or modify sign-up data before registration |
preAuthentication |
Run logic before authentication completes |
preTokenGeneration |
Customize token claims before token issuance |
preTokenGenerationConfig |
Configure token generation settings |
postAuthentication |
Run logic after successful authentication |
postConfirmation |
Run logic after user account confirmation |
userMigration |
Migrate users from an external system on sign-in |
createAuthChallenge |
Create a custom authentication challenge |
defineAuthChallenge |
Define the flow of custom authentication challenges |
verifyAuthChallengeResponse |
Verify the response to a custom challenge |
customMessage |
Customize verification and MFA messages |
customEmailSender |
Custom email delivery logic |
customSmsSender |
Custom SMS delivery logic |
Each trigger method can accept a lambda option for custom Lambda settings:
@Trigger({ type: 'preSignUp', lambda: { memory: 512, timeout: 30 } })
validateSignUp(@Event() event: any) { }Extending the Auth Stack
Use the extend callback to access underlying CDKTN resources and apply advanced configuration:
new AuthResolver({
name: 'app-auth',
extend: ({ userPool, userPoolClient, scope }) => {
// Add custom domains, resource servers, or any CDKTN construct
},
});