There are more AWS SDK examples available in the AWS Doc SDK Examples
Getting started with Amazon Cognito user pools
The following code example shows how to:
Create a user pool
Create an app client
Set up a domain for your user pool
Create a user as an administrator
Enable self-registration
List users in the user pool
Clean up resources
- Bash
-
- AWS CLI with Bash script
-
Note
There's more on GitHub. Find the complete example and learn how to set up and run in the Sample developer tutorials
repository. #!/bin/bash # Amazon Cognito User Pools Getting Started Script # This script creates and configures an Amazon Cognito user pool with an app client set -euo pipefail # Security: Set restrictive umask umask 0077 # Set up logging with secure permissions LOG_FILE="cognito-user-pool-setup.log" touch "$LOG_FILE" chmod 600 "$LOG_FILE" exec > >(tee -a "$LOG_FILE") 2>&1 echo "Starting Amazon Cognito User Pool setup script at $(date)" echo "All commands and outputs will be logged to $LOG_FILE" # Function to check for errors in command output check_error() { local output=$1 local cmd=$2 if echo "$output" | grep -qi "error\|failed"; then echo "ERROR: Command failed: $cmd" >&2 echo "Output: $output" >&2 cleanup_on_error exit 1 fi } # Function to check AWS CLI return code check_aws_error() { local exit_code=$? local cmd=$1 if [ $exit_code -ne 0 ]; then echo "ERROR: AWS CLI command failed with exit code $exit_code: $cmd" >&2 cleanup_on_error exit "$exit_code" fi } # Function to clean up resources on error cleanup_on_error() { echo "Error encountered. Attempting to clean up resources..." >&2 if [ -n "${DOMAIN_NAME:-}" ] && [ -n "${USER_POOL_ID:-}" ]; then echo "Deleting user pool domain: $DOMAIN_NAME" >&2 aws cognito-idp delete-user-pool-domain \ --user-pool-id "$USER_POOL_ID" \ --domain "$DOMAIN_NAME" 2>/dev/null || true fi if [ -n "${USER_POOL_ID:-}" ]; then echo "Deleting user pool: $USER_POOL_ID" >&2 aws cognito-idp delete-user-pool \ --user-pool-id "$USER_POOL_ID" 2>/dev/null || true fi } # Set trap for cleanup on exit trap cleanup_on_error EXIT ERR # Validate AWS CLI is installed and configured if ! command -v aws &> /dev/null; then echo "ERROR: AWS CLI is not installed" >&2 exit 1 fi # Validate jq is installed if ! command -v jq &> /dev/null; then echo "ERROR: jq is not installed" >&2 exit 1 fi # Validate openssl is installed if ! command -v openssl &> /dev/null; then echo "ERROR: openssl is not installed" >&2 exit 1 fi if ! aws sts get-caller-identity &> /dev/null; then echo "ERROR: AWS CLI is not configured or credentials are invalid" >&2 exit 1 fi # Get the current AWS region AWS_REGION=$(aws configure get region) if [ -z "$AWS_REGION" ]; then AWS_REGION="us-east-1" # Default region if not configured fi echo "Using AWS Region: $AWS_REGION" # Validate region format if ! [[ "$AWS_REGION" =~ ^[a-z]{2}-[a-z]+-[0-9]{1}$ ]]; then echo "ERROR: Invalid AWS region format: $AWS_REGION" >&2 exit 1 fi # Generate random identifier for resource names using secure method RANDOM_ID=$(openssl rand -hex 6) if [ -z "$RANDOM_ID" ]; then echo "ERROR: Failed to generate random identifier" >&2 exit 1 fi USER_POOL_NAME="MyUserPool-${RANDOM_ID}" APP_CLIENT_NAME="MyAppClient-${RANDOM_ID}" DOMAIN_NAME="my-auth-domain-${RANDOM_ID}" # Validate resource names don't exceed limits if [ ${#USER_POOL_NAME} -gt 128 ]; then echo "ERROR: User pool name exceeds maximum length of 128 characters" >&2 exit 1 fi if [ ${#APP_CLIENT_NAME} -gt 128 ]; then echo "ERROR: App client name exceeds maximum length of 128 characters" >&2 exit 1 fi echo "Using random identifier: $RANDOM_ID" echo "User pool name: $USER_POOL_NAME" echo "App client name: $APP_CLIENT_NAME" echo "Domain name: $DOMAIN_NAME" # Step 1: Create a User Pool echo "Creating user pool..." USER_POOL_OUTPUT=$(aws cognito-idp create-user-pool \ --pool-name "$USER_POOL_NAME" \ --auto-verified-attributes email \ --username-attributes email \ --policies '{"PasswordPolicy":{"MinimumLength":12,"RequireUppercase":true,"RequireLowercase":true,"RequireNumbers":true,"RequireSymbols":true}}' \ --schema '[{"Name":"email","Required":true,"Mutable":true}]' \ --mfa-configuration OFF \ --user-attribute-update-settings '{"AttributesRequireVerificationBeforeUpdate":["email"]}' \ --account-recovery-setting 'RecoveryMechanisms=[{Name=verified_email,Priority=1}]' \ --deletion-protection INACTIVE \ --region "$AWS_REGION" \ 2>&1) check_aws_error "create-user-pool" # Extract the User Pool ID using jq for safety USER_POOL_ID=$(echo "$USER_POOL_OUTPUT" | jq -r '.UserPool.Id // empty') if [ -z "$USER_POOL_ID" ]; then echo "ERROR: Failed to extract User Pool ID" >&2 exit 1 fi # Validate User Pool ID format if ! [[ "$USER_POOL_ID" =~ ^[a-z]{2}-[a-z]+-[0-9]+_[a-zA-Z0-9]+$ ]]; then echo "ERROR: Invalid User Pool ID format: $USER_POOL_ID" >&2 exit 1 fi echo "User Pool created with ID: $USER_POOL_ID" # Wait for user pool to be ready echo "Waiting for user pool to be ready..." sleep 5 # Step 2: Create an App Client with enhanced security echo "Creating app client..." APP_CLIENT_OUTPUT=$(aws cognito-idp create-user-pool-client \ --user-pool-id "$USER_POOL_ID" \ --client-name "$APP_CLIENT_NAME" \ --no-generate-secret \ --explicit-auth-flows ALLOW_REFRESH_TOKEN_AUTH ALLOW_USER_PASSWORD_AUTH \ --callback-urls '["https://localhost:3000/callback"]' \ --allowed-o-auth-flows 'code' \ --allowed-o-auth-scopes 'openid' 'email' 'profile' \ --allowed-o-auth-flows-user-pool-client \ --prevent-user-existence-errors ENABLED \ --enable-token-revocation \ --access-token-validity 1 \ --id-token-validity 1 \ --refresh-token-validity 30 \ --token-validity-units 'AccessToken=hours,IdToken=hours,RefreshToken=days' \ --region "$AWS_REGION" \ 2>&1) check_aws_error "create-user-pool-client" # Extract the Client ID using jq for safety CLIENT_ID=$(echo "$APP_CLIENT_OUTPUT" | jq -r '.UserPoolClient.ClientId // empty') if [ -z "$CLIENT_ID" ]; then echo "ERROR: Failed to extract Client ID" >&2 cleanup_on_error exit 1 fi # Validate Client ID format if ! [[ "$CLIENT_ID" =~ ^[a-z0-9]{26}$ ]]; then echo "ERROR: Invalid Client ID format: $CLIENT_ID" >&2 cleanup_on_error exit 1 fi echo "App Client created with ID: $CLIENT_ID" # Step 3: Set Up a Domain for Your User Pool echo "Setting up user pool domain..." DOMAIN_OUTPUT=$(aws cognito-idp create-user-pool-domain \ --user-pool-id "$USER_POOL_ID" \ --domain "$DOMAIN_NAME" \ --region "$AWS_REGION" \ 2>&1) check_aws_error "create-user-pool-domain" echo "Domain created: $DOMAIN_NAME.auth.$AWS_REGION.amazoncognito.com" # Step 4: View User Pool Details echo "Retrieving user pool details..." USER_POOL_DETAILS=$(aws cognito-idp describe-user-pool \ --user-pool-id "$USER_POOL_ID" \ --region "$AWS_REGION" \ 2>&1) check_aws_error "describe-user-pool" echo "User Pool details retrieved successfully" # Step 5: View App Client Details echo "Retrieving app client details..." APP_CLIENT_DETAILS=$(aws cognito-idp describe-user-pool-client \ --user-pool-id "$USER_POOL_ID" \ --client-id "$CLIENT_ID" \ --region "$AWS_REGION" \ 2>&1) check_aws_error "describe-user-pool-client" echo "App Client details retrieved successfully" # Step 6: Create a User (Admin) echo "Creating admin user..." ADMIN_USER_EMAIL="admin@example.com" TEMP_PASSWORD="$(openssl rand -base64 12 | tr -d '\n')!@#" if [ -z "$TEMP_PASSWORD" ]; then echo "ERROR: Failed to generate temporary password" >&2 cleanup_on_error exit 1 fi ADMIN_USER_OUTPUT=$(aws cognito-idp admin-create-user \ --user-pool-id "$USER_POOL_ID" \ --username "$ADMIN_USER_EMAIL" \ --user-attributes Name=email,Value="$ADMIN_USER_EMAIL" Name=email_verified,Value=true \ --temporary-password "$TEMP_PASSWORD" \ --message-action SUPPRESS \ --region "$AWS_REGION" \ 2>&1) check_aws_error "admin-create-user" echo "Admin user created: $ADMIN_USER_EMAIL" # Securely clear temporary password from memory unset TEMP_PASSWORD # Step 7: Self-Registration echo "Demonstrating self-registration..." USER_EMAIL="user@example.com" USER_PASSWORD="SecurePassword123!" SIGNUP_OUTPUT=$(aws cognito-idp sign-up \ --client-id "$CLIENT_ID" \ --username "$USER_EMAIL" \ --password "$USER_PASSWORD" \ --user-attributes Name=email,Value="$USER_EMAIL" \ --region "$AWS_REGION" \ 2>&1) check_aws_error "sign-up" echo "User signed up: $USER_EMAIL" echo "A confirmation code would be sent to the user's email in a real scenario" # Securely clear password from memory unset USER_PASSWORD echo "" echo "===================================================" echo "IMPORTANT: In a real scenario, the user would receive" echo "a confirmation code via email. For this demo, we'll" echo "use admin-confirm-sign-up instead." echo "===================================================" echo "" # Step 8: Confirm User Registration (using admin privileges for demo) echo "Confirming user registration (admin method)..." CONFIRM_OUTPUT=$(aws cognito-idp admin-confirm-sign-up \ --user-pool-id "$USER_POOL_ID" \ --username "$USER_EMAIL" \ --region "$AWS_REGION" \ 2>&1) check_aws_error "admin-confirm-sign-up" echo "User confirmed: $USER_EMAIL" # Step 9: Set permanent password for user echo "Setting permanent password for user..." SET_PASSWORD="SecureUserPassword123!" SET_PASS_OUTPUT=$(aws cognito-idp admin-set-user-password \ --user-pool-id "$USER_POOL_ID" \ --username "$USER_EMAIL" \ --password "$SET_PASSWORD" \ --permanent \ --region "$AWS_REGION" \ 2>&1) check_aws_error "admin-set-user-password" echo "Permanent password set for user" unset SET_PASSWORD # Step 10: Authenticate a User echo "Authenticating user..." AUTH_PASSWORD="SecureUserPassword123!" AUTH_OUTPUT=$(aws cognito-idp initiate-auth \ --client-id "$CLIENT_ID" \ --auth-flow USER_PASSWORD_AUTH \ --auth-parameters "USERNAME=$USER_EMAIL,PASSWORD=$AUTH_PASSWORD" \ --region "$AWS_REGION" \ 2>&1) check_aws_error "initiate-auth" echo "User authenticated successfully" unset AUTH_PASSWORD # Extract auth tokens securely ID_TOKEN=$(echo "$AUTH_OUTPUT" | jq -r '.AuthenticationResult.IdToken // empty') ACCESS_TOKEN=$(echo "$AUTH_OUTPUT" | jq -r '.AuthenticationResult.AccessToken // empty') # Validate tokens exist if [ -z "$ID_TOKEN" ] || [ -z "$ACCESS_TOKEN" ]; then echo "WARNING: Failed to extract authentication tokens" >&2 else echo "Authentication tokens obtained successfully" fi # Securely clear tokens from memory unset ID_TOKEN unset ACCESS_TOKEN # Step 11: List Users in the User Pool echo "Listing users in the user pool..." USERS_OUTPUT=$(aws cognito-idp list-users \ --user-pool-id "$USER_POOL_ID" \ --region "$AWS_REGION" \ 2>&1) check_aws_error "list-users" echo "Users listed successfully" # Display summary of created resources echo "" echo "===================================================" echo "RESOURCE SUMMARY" echo "===================================================" echo "User Pool ID: $USER_POOL_ID" echo "User Pool Name: $USER_POOL_NAME" echo "App Client ID: $CLIENT_ID" echo "App Client Name: $APP_CLIENT_NAME" echo "Domain: $DOMAIN_NAME.auth.$AWS_REGION.amazoncognito.com" echo "Admin User: $ADMIN_USER_EMAIL" echo "Regular User: $USER_EMAIL" echo "===================================================" echo "" # Auto-confirm cleanup echo "" echo "===========================================" echo "CLEANUP" echo "===========================================" echo "Starting cleanup process..." # Step 12: Clean Up Resources echo "Deleting user pool domain..." DELETE_DOMAIN_OUTPUT=$(aws cognito-idp delete-user-pool-domain \ --user-pool-id "$USER_POOL_ID" \ --domain "$DOMAIN_NAME" \ --region "$AWS_REGION" \ 2>&1) check_aws_error "delete-user-pool-domain" echo "Domain deleted successfully" # Wait for domain deletion to complete echo "Waiting for domain deletion to complete..." sleep 5 echo "Deleting user pool (this will also delete the app client)..." DELETE_POOL_OUTPUT=$(aws cognito-idp delete-user-pool \ --user-pool-id "$USER_POOL_ID" \ --region "$AWS_REGION" \ 2>&1) check_aws_error "delete-user-pool" echo "User pool deleted successfully" echo "All resources have been cleaned up" echo "Script completed at $(date)" # Remove trap to prevent cleanup on successful exit trap - EXIT ERR-
For API details, see the following topics in AWS CLI Command Reference.
-
Automatically migrate known users with a Lambda function
Sign up a user with a user pool that requires MFA