The aws:cognito/userPool:UserPool resource, part of the Pulumi AWS provider, defines a Cognito User Pool that manages user registration, authentication, and account recovery. This guide focuses on three capabilities: basic pool creation, MFA configuration, and account recovery settings.
User pools require IAM roles for SMS delivery and may integrate with SES for email, Lambda for custom workflows, and other AWS services. The examples are intentionally small. Combine them with your own password policies, email configuration, and custom attributes.
Create a minimal user pool with a name
Most deployments start by creating a user pool with a unique name, establishing the container for authentication.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const pool = new aws.cognito.UserPool("pool", {name: "mypool"});
import pulumi
import pulumi_aws as aws
pool = aws.cognito.UserPool("pool", name="mypool")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cognito"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cognito.NewUserPool(ctx, "pool", &cognito.UserPoolArgs{
Name: pulumi.String("mypool"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var pool = new Aws.Cognito.UserPool("pool", new()
{
Name = "mypool",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cognito.UserPool;
import com.pulumi.aws.cognito.UserPoolArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var pool = new UserPool("pool", UserPoolArgs.builder()
.name("mypool")
.build());
}
}
resources:
pool:
type: aws:cognito:UserPool
properties:
name: mypool
The name property sets a unique identifier for the pool. Without additional configuration, the pool uses Cognito defaults: MFA is OFF, password policy follows AWS standards, and email delivery uses Cognito’s built-in service.
Enable SMS and authenticator app MFA
Applications requiring stronger authentication enable MFA to require a second factor beyond username and password.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.cognito.UserPool("example", {
mfaConfiguration: "ON",
smsAuthenticationMessage: "Your code is {####}",
smsConfiguration: {
externalId: "example",
snsCallerArn: exampleAwsIamRole.arn,
snsRegion: "us-east-1",
},
softwareTokenMfaConfiguration: {
enabled: true,
},
});
import pulumi
import pulumi_aws as aws
example = aws.cognito.UserPool("example",
mfa_configuration="ON",
sms_authentication_message="Your code is {####}",
sms_configuration={
"external_id": "example",
"sns_caller_arn": example_aws_iam_role["arn"],
"sns_region": "us-east-1",
},
software_token_mfa_configuration={
"enabled": True,
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cognito"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cognito.NewUserPool(ctx, "example", &cognito.UserPoolArgs{
MfaConfiguration: pulumi.String("ON"),
SmsAuthenticationMessage: pulumi.String("Your code is {####}"),
SmsConfiguration: &cognito.UserPoolSmsConfigurationArgs{
ExternalId: pulumi.String("example"),
SnsCallerArn: pulumi.Any(exampleAwsIamRole.Arn),
SnsRegion: pulumi.String("us-east-1"),
},
SoftwareTokenMfaConfiguration: &cognito.UserPoolSoftwareTokenMfaConfigurationArgs{
Enabled: pulumi.Bool(true),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Cognito.UserPool("example", new()
{
MfaConfiguration = "ON",
SmsAuthenticationMessage = "Your code is {####}",
SmsConfiguration = new Aws.Cognito.Inputs.UserPoolSmsConfigurationArgs
{
ExternalId = "example",
SnsCallerArn = exampleAwsIamRole.Arn,
SnsRegion = "us-east-1",
},
SoftwareTokenMfaConfiguration = new Aws.Cognito.Inputs.UserPoolSoftwareTokenMfaConfigurationArgs
{
Enabled = true,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cognito.UserPool;
import com.pulumi.aws.cognito.UserPoolArgs;
import com.pulumi.aws.cognito.inputs.UserPoolSmsConfigurationArgs;
import com.pulumi.aws.cognito.inputs.UserPoolSoftwareTokenMfaConfigurationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new UserPool("example", UserPoolArgs.builder()
.mfaConfiguration("ON")
.smsAuthenticationMessage("Your code is {####}")
.smsConfiguration(UserPoolSmsConfigurationArgs.builder()
.externalId("example")
.snsCallerArn(exampleAwsIamRole.arn())
.snsRegion("us-east-1")
.build())
.softwareTokenMfaConfiguration(UserPoolSoftwareTokenMfaConfigurationArgs.builder()
.enabled(true)
.build())
.build());
}
}
resources:
example:
type: aws:cognito:UserPool
properties:
mfaConfiguration: ON
smsAuthenticationMessage: Your code is {####}
smsConfiguration:
externalId: example
snsCallerArn: ${exampleAwsIamRole.arn}
snsRegion: us-east-1
softwareTokenMfaConfiguration:
enabled: true
Setting mfaConfiguration to “ON” requires all users to provide a second factor. The smsConfiguration block enables SMS codes by specifying an IAM role with SNS permissions and the region for SMS delivery. The softwareTokenMfaConfiguration block enables TOTP codes from authenticator apps. The smsAuthenticationMessage defines the template for SMS codes, where {####} is replaced with the actual code.
Configure password recovery methods
Users who forget passwords need a way to recover access through verified contact methods.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const test = new aws.cognito.UserPool("test", {
name: "mypool",
accountRecoverySetting: {
recoveryMechanisms: [
{
name: "verified_email",
priority: 1,
},
{
name: "verified_phone_number",
priority: 2,
},
],
},
});
import pulumi
import pulumi_aws as aws
test = aws.cognito.UserPool("test",
name="mypool",
account_recovery_setting={
"recovery_mechanisms": [
{
"name": "verified_email",
"priority": 1,
},
{
"name": "verified_phone_number",
"priority": 2,
},
],
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cognito"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cognito.NewUserPool(ctx, "test", &cognito.UserPoolArgs{
Name: pulumi.String("mypool"),
AccountRecoverySetting: &cognito.UserPoolAccountRecoverySettingArgs{
RecoveryMechanisms: cognito.UserPoolAccountRecoverySettingRecoveryMechanismArray{
&cognito.UserPoolAccountRecoverySettingRecoveryMechanismArgs{
Name: pulumi.String("verified_email"),
Priority: pulumi.Int(1),
},
&cognito.UserPoolAccountRecoverySettingRecoveryMechanismArgs{
Name: pulumi.String("verified_phone_number"),
Priority: pulumi.Int(2),
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var test = new Aws.Cognito.UserPool("test", new()
{
Name = "mypool",
AccountRecoverySetting = new Aws.Cognito.Inputs.UserPoolAccountRecoverySettingArgs
{
RecoveryMechanisms = new[]
{
new Aws.Cognito.Inputs.UserPoolAccountRecoverySettingRecoveryMechanismArgs
{
Name = "verified_email",
Priority = 1,
},
new Aws.Cognito.Inputs.UserPoolAccountRecoverySettingRecoveryMechanismArgs
{
Name = "verified_phone_number",
Priority = 2,
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cognito.UserPool;
import com.pulumi.aws.cognito.UserPoolArgs;
import com.pulumi.aws.cognito.inputs.UserPoolAccountRecoverySettingArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var test = new UserPool("test", UserPoolArgs.builder()
.name("mypool")
.accountRecoverySetting(UserPoolAccountRecoverySettingArgs.builder()
.recoveryMechanisms(
UserPoolAccountRecoverySettingRecoveryMechanismArgs.builder()
.name("verified_email")
.priority(1)
.build(),
UserPoolAccountRecoverySettingRecoveryMechanismArgs.builder()
.name("verified_phone_number")
.priority(2)
.build())
.build())
.build());
}
}
resources:
test:
type: aws:cognito:UserPool
properties:
name: mypool
accountRecoverySetting:
recoveryMechanisms:
- name: verified_email
priority: 1
- name: verified_phone_number
priority: 2
The accountRecoverySetting block defines recovery mechanisms with priority order. When a user requests password recovery, Cognito tries verified_email first (priority 1), then verified_phone_number (priority 2). Users must verify these attributes during registration for recovery to work.
Beyond these examples
These snippets focus on specific user pool features: basic pool creation, MFA configuration (SMS and TOTP), and account recovery mechanisms. They’re intentionally minimal rather than full authentication systems.
The examples may reference pre-existing infrastructure such as IAM roles with SNS permissions for SMS delivery. They focus on configuring the user pool rather than provisioning everything around it.
To keep things focused, common user pool patterns are omitted, including:
- Password policies (passwordPolicy)
- Email configuration and SES integration (emailConfiguration)
- Custom attributes and schema (schemas)
- Lambda triggers for custom workflows (lambdaConfig)
- Advanced security features (userPoolAddOns)
- Username and alias configuration (usernameAttributes, aliasAttributes)
These omissions are intentional: the goal is to illustrate how each user pool feature is wired, not provide drop-in authentication modules. See the Cognito User Pool resource reference for all available configuration options.
Let's create AWS Cognito User Pools
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration Conflicts & Immutability
aliasAttributes and usernameAttributes are immutable. Schema attributes can be added but never modified or removed. Plan these carefully at creation time.aliasAttributes and usernameAttributes conflict with each other. Choose one approach for username configuration at creation time.emailVerificationMessage conflicts with verificationMessageTemplate.emailMessage, emailVerificationSubject conflicts with verificationMessageTemplate.emailSubject, and smsVerificationMessage conflicts with verificationMessageTemplate.smsMessage. Use one approach or the other, not both.Multi-Factor Authentication (MFA)
mfaConfiguration has three values: OFF (default, no MFA required), ON (required for all users), or OPTIONAL (per-user MFA). Both ON and OPTIONAL require at least one of emailMfaConfiguration, smsConfiguration, or softwareTokenMfaConfiguration to be configured.accountRecoverySetting entries and an emailConfiguration block. It only works when mfaConfiguration is ON or OPTIONAL.mfaConfiguration to ON, configure smsConfiguration with your SNS caller ARN and region, and set softwareTokenMfaConfiguration.enabled to true.SMS Configuration
smsConfiguration once applied. The resource ignores removal attempts to protect user data. Use the taint command to force recreation if you need to remove it.smsAuthenticationMessage must contain the {####} placeholder, which gets replaced with the verification code.Schema & Attributes
Account Recovery & Security
accountRecoverySetting with recoveryMechanisms, specifying name (verified_email or verified_phone_number) and priority for each mechanism.deletionProtection to ACTIVE. You must change it back to INACTIVE before you can delete the pool. The default is INACTIVE.LITE, ESSENTIALS, and PLUS. Configure this using the userPoolTier property.