UNPKG

@ssktechnologies/awsforge

Version:

Enterprise-grade AWS Cognito authentication toolkit for seamless user management, registration, login, and password recovery with JWT token handling

492 lines (379 loc) 10.8 kB
# AWSForge Enterprise-grade AWS Cognito authentication module for Node.js applications with TypeScript support. ## Features - User registration with email OTP confirmation - Secure login with Cognito JWT tokens - Password recovery and reset flows - Token verification and refresh - Custom attribute validation - User profile management - Full TypeScript support - ESM ready - Multiple usage patterns (functional, class-based, service-based) ## Installation ```bash npm install awsforge ``` ## Environment Configuration All environment variables are required for proper functionality: ```env AWS_REGION=us-east-1 USER_POOL_ID=your_cognito_user_pool_id CLIENT_ID=your_cognito_app_client_id CLIENT_SECRET=your_cognito_app_client_secret ``` **Note**: AWS credentials are no longer required as direct environment variables. The library uses the standard AWS credential provider chain, which will look for credentials in the following order: 1. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) 2. Shared credentials file (~/.aws/credentials) 3. ECS container credentials 4. EC2 instance profile credentials 5. Lambda function credentials This enables more secure credential management and better compatibility with AWS services like Lambda. ## Usage Patterns AWSForge offers multiple ways to use the library based on your preferences: ### 1. Functional API (Recommended) The simplest way to get started with a functional approach: ```typescript import createCognito from 'awsforge'; const cognito = createCognito({ region: process.env.AWS_REGION, userPoolId: process.env.USER_POOL_ID, clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, }); // Quick registration const result = await cognito.register({ username: 'john_doe', password: 'SecurePassword123!', email: 'john@example.com', firstName: 'John', lastName: 'Doe' }); // Quick login const loginResult = await cognito.login({ username: 'john@example.com', password: 'SecurePassword123!' }); ``` ### 2. Class-based API For a more structured approach: ```typescript import { AWSForge } from 'awsforge'; const aws = new AWSForge({ region: process.env.AWS_REGION, userPoolId: process.env.USER_POOL_ID, clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, }); // Use cognito methods const result = await aws.cognito.register({ username: 'john_doe', password: 'SecurePassword123!', email: 'john@example.com' }); // Access utilities const tokens = aws.utils.extractTokens(loginResult); ``` ### 3. Service-based API (Original) For full control and advanced configurations: ```typescript import { CognitoService, CognitoConfigs } from 'awsforge'; // Initialize with custom attributes const cognito = new CognitoService( CognitoConfigs.withCustomAttributes( { region: process.env.AWS_REGION, userPoolId: process.env.USER_POOL_ID, clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, }, ['plan', 'role'] // Allowed custom attributes ) ); ``` ## API Reference ### User Registration Register a new user with email confirmation: ```typescript // Functional API const registrationResult = await cognito.register({ username: 'john_doe', password: 'SecurePassword123!', email: 'john@example.com', firstName: 'John', lastName: 'Doe', phoneNumber: '+1234567890', customAttributes: { plan: 'premium', role: 'user' } }); // Class-based API const registrationResult = await aws.cognito.register({ username: 'john_doe', password: 'SecurePassword123!', email: 'john@example.com', firstName: 'John', lastName: 'Doe' }); // Service-based API const registrationResult = await cognitoService.registerUser({ username: 'john_doe', password: 'SecurePassword123!', email: 'john@example.com', firstName: 'John', lastName: 'Doe' }); ``` ### Confirm Registration Confirm user registration with OTP code: ```typescript // Functional API await cognito.confirmRegistration({ username: 'john@example.com', confirmationCode: '123456' }); // Class-based API await aws.cognito.confirmRegistration({ username: 'john@example.com', confirmationCode: '123456' }); // Service-based API await cognitoService.confirmUserRegistration({ username: 'john@example.com', confirmationCode: '123456' }); ``` ### User Login Authenticate user and receive JWT tokens: ```typescript // All APIs support the same login method const loginResult = await cognito.login({ username: 'john@example.com', password: 'SecurePassword123!' }); // Access tokens from result const { AccessToken, IdToken, RefreshToken } = loginResult.AuthenticationResult; ``` ### Token Verification Verify JWT tokens: ```typescript // Verify access token (all APIs) const accessTokenResult = await cognito.verifyAccessToken(accessToken); if (accessTokenResult.isValid) { console.log('Token is valid:', accessTokenResult.decoded); } else { console.error('Token error:', accessTokenResult.error); } // Verify ID token const idTokenResult = await cognito.verifyIdToken(idToken); // Generic token verification const tokenResult = await cognito.verifyToken(anyToken); ``` ### Get User Profile Retrieve user information using access token: ```typescript const userProfile = await cognito.getUserFromToken(accessToken); console.log('User:', userProfile.username); console.log('Attributes:', userProfile.attributes); ``` ### Refresh Tokens Refresh expired access tokens: ```typescript const refreshResult = await cognito.refreshTokens(refreshToken); const newAccessToken = refreshResult.AuthenticationResult?.AccessToken; ``` ### Password Reset Initiate password reset flow: ```typescript // Send reset code (functional/class API) await cognito.forgotPassword({ username: 'john@example.com' }); // Service API await cognitoService.initiateForgotPassword({ username: 'john@example.com' }); // Confirm new password with code (all APIs) await cognito.confirmForgotPassword({ username: 'john@example.com', confirmationCode: '123456', newPassword: 'NewSecurePassword123!' }); ``` ### Change Password Change password for authenticated user: ```typescript await cognito.changePassword({ accessToken: accessToken, previousPassword: 'OldPassword123!', proposedPassword: 'NewPassword123!' }); ``` ### Additional Operations ```typescript // Resend confirmation code await cognito.resendConfirmationCode('john@example.com'); // Delete user account await cognito.deleteUser(accessToken); // Revoke token await cognito.revokeToken(refreshToken); ``` ## Configuration Options ### Functional API Configuration ```typescript import createCognito from 'awsforge'; // Basic configuration const cognito = createCognito({ region: process.env.AWS_REGION, userPoolId: process.env.USER_POOL_ID, clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, }); // Access configuration presets const { minimal, withCustomAttributes, permissive } = cognito.configs; ``` ### Class-based API Configuration ```typescript import { AWSForge } from 'awsforge'; const aws = new AWSForge({ region: process.env.AWS_REGION, userPoolId: process.env.USER_POOL_ID, clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, }); // Access configuration presets const configs = AWSForge.configs; ``` ### Service-based API Configuration #### Minimal Configuration No custom attributes allowed: ```typescript import { CognitoService, CognitoConfigs } from 'awsforge'; const cognito = new CognitoService( CognitoConfigs.minimal({ region: process.env.AWS_REGION, userPoolId: process.env.USER_POOL_ID, clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, }) ); ``` #### Custom Attributes Specify allowed custom attributes: ```typescript const cognito = new CognitoService( CognitoConfigs.withCustomAttributes(baseConfig, ['plan', 'role', 'department']) ); ``` #### Permissive Mode Disable custom attribute validation (use with caution): ```typescript const cognito = new CognitoService( CognitoConfigs.permissive(baseConfig) ); ``` ## Token Utilities Extract tokens from login response: ```typescript import { extractTokens } from 'awsforge'; // or import createCognito from 'awsforge'; const cognito = createCognito(config); // Direct import const tokens = extractTokens(loginResult); // Via functional API const tokens = cognito.utils.extractTokens(loginResult); // Via class API const aws = new AWSForge(config); const tokens = aws.utils.extractTokens(loginResult); console.log('Access Token:', tokens.accessToken); console.log('ID Token:', tokens.idToken); console.log('Refresh Token:', tokens.refreshToken); ``` ## Import Options ### Default Import (Functional API) ```typescript import createCognito from 'awsforge'; const cognito = createCognito(config); ``` ### Named Imports ```typescript import { AWSForge, CognitoService, CognitoConfigs, extractTokens } from 'awsforge'; ``` ### Mixed Imports ```typescript import createCognito, { AWSForge, extractTokens } from 'awsforge'; ``` ### Type Imports ```typescript import type { AWSForgeConfig, UserRegistrationData, UserLoginData, AuthTokens, AuthResponse, TokenVerificationResult, UserProfile, ChangePasswordData, ConfirmForgotPasswordData } from 'awsforge'; ``` ## Error Handling All methods throw descriptive errors. Always wrap calls in try-catch blocks: ```typescript try { await cognito.register(userData); } catch (error) { if (error.name === 'UsernameExistsException') { console.error('User already exists'); } else if (error.name === 'InvalidParameterException') { console.error('Invalid parameters provided'); } else { console.error('Registration failed:', error.message); } } ``` ## Migration Guide ### From Service-based to Functional API **Before:** ```typescript import { CognitoService, CognitoConfigs } from 'awsforge'; const cognito = new CognitoService(CognitoConfigs.minimal(config)); await cognito.registerUser(userData); ``` **After:** ```typescript import createCognito from 'awsforge'; const cognito = createCognito(config); await cognito.register(userData); ``` ### From Service-based to Class-based API **Before:** ```typescript import { CognitoService } from 'awsforge'; const cognito = new CognitoService(config); await cognito.registerUser(userData); ``` **After:** ```typescript import { AWSForge } from 'awsforge'; const aws = new AWSForge(config); await aws.cognito.register(userData); ``` ## Development Run tests locally: ```bash npm test ``` Build the project: ```bash npm run build ``` ## License MIT © 2025 Avdhut Noola Contributions welcome via GitHub issues or pull requests.