I have a localstack cognito user pool set up via the following .tf
:
provider "aws" {
region = "us-east-1" # Change to your desired region
access_key = "test" # Access key for LocalStack
secret_key = "test" # Secret key for LocalStack
skip_credentials_validation = true
skip_requesting_account_id = true
skip_metadata_api_check = true
endpoints {
iam = "http://localhost:4566"
cognitoidp = "http://localhost:4566"
}
}
resource "aws_cognito_user_pool" "main_user_pool" {
name = "main_user_pool"
account_recovery_setting {
recovery_mechanism {
name = "verified_email"
priority = 1
}
recovery_mechanism {
name = "verified_phone_number"
priority = 2
}
}
# Define the attributes for the user pool
# Ensure that only standard attributes are marked as required
schema {
name = "email"
attribute_data_type = "String"
mutable = true
required = true
}
password_policy {
minimum_length = 6
require_lowercase = true
require_numbers = true
require_symbols = true
require_uppercase = true
}
email_configuration {
email_sending_account = "COGNITO_DEFAULT"
}
username_attributes = ["email"]
auto_verified_attributes = ["email"]
# allow users to sign in with their email as well as their username
username_configuration {
case_sensitive = true
}
}
resource "aws_cognito_user_pool_client" "userpool_client" {
name = "my-client"
user_pool_id = aws_cognito_user_pool.main_user_pool.id
generate_secret = false # No client secret for a public client like a mobile app
}
output "user_pool_client_id" {
value = aws_cognito_user_pool_client.userpool_client.id
}
I have the line auto_verified_attributes = ["email"]
and so I expected any signed-up user to become immediately verified by default.
I have my swift app sign up users with the following code:
func registerUser(email: String, password: String) {
let serviceConfiguration = AWSServiceConfiguration(region: .USEast1,
credentialsProvider: nil)
AWSServiceManager.default().defaultServiceConfiguration = serviceConfiguration
let signUpRequest = AWSCognitoIdentityProviderSignUpRequest()!
signUpRequest.clientId = CognitoConfig.clientId
signUpRequest.username = email
signUpRequest.password = password
// Define user attributes here - e.g., email
let emailAttribute = AWSCognitoIdentityUserAttributeType()
emailAttribute?.name = "email"
emailAttribute?.value = email
signUpRequest.userAttributes = [emailAttribute!]
// Get the service provider instance
let cognitoProvider = AWSCognitoIdentityProvider(forKey: "LocalStackCognito")
// Perform the sign-up
cognitoProvider.signUp(signUpRequest).continueWith { task -> AnyObject? in
DispatchQueue.main.async {
if let error = task.error {
print("Registration Error: \(error)")
//passwrod too short pass doesn't seem human readable
errorMessage = error.localizedDescription
} else {
print("Registration Success")
loginUser(email: email, password: password)
// Handle successful registration, e.g., show confirmation code UI.
}
}
return nil
}
}
If I describe the pool via awslocal cognito-idp describe-user-pool --user-pool-id "<userpoolid>"
I can see in the response that the email is an autoverified attribute:
...
,
"AutoVerifiedAttributes": [
"email"
],
"UsernameAttributes": [
"email"
],
"VerificationMessageTemplate": {
"DefaultEmailOption": "CONFIRM_WITH_CODE"
},
"UserAttributeUpdateSettings": {
"AttributesRequireVerificationBeforeUpdate": []
},
...
However when I sign up and then list the users via awslocal cognito-idp list-users --user-pool-id "<userpoolid>"
I get:
{
"Users": [
{
"Username": "141bd541-2d8a-4c55-8ebd-83296e1ff99b",
"Attributes": [
{
"Name": "cognito:username",
"Value": "test99@gmail.com"
},
{
"Name": "email",
"Value": "test99@gmail.com"
},
{
"Name": "sub",
"Value": "141bd541-2d8a-4c55-8ebd-83296e1ff99b"
},
{
"Name": "email_verified",
"Value": "false"
}
],
"UserCreateDate": 1710631590.379655,
"UserLastModifiedDate": 1710631590.379655,
"Enabled": true,
"UserStatus": "UNCONFIRMED"
}
]
}
The email_verified
is false
and the UserStatus
is UNCONFIRMED
. I don't understand what I am doing wrong. The terraform appears set up correctly and I can verify it via the pool description. What am I missing?
Sigh. Turns out the entire premise of my question is wrong. There is (as far as I can tell reading the docs more thoroughly) no way to IaC define the user pool to automatically verify users. Hence, the solution exists not in the terraform, but in manually confirming the user after registration via adminConfirmSignUp
.
func confirmUser(email: String) {
let confirmSignUpRequest = AWSCognitoIdentityProviderAdminConfirmSignUpRequest()!
confirmSignUpRequest.userPoolId = "<user_pool_id>"
confirmSignUpRequest.username = email
let cognitoProvider = AWSCognitoIdentityProvider(forKey: "LocalStackCognito")
cognitoProvider.adminConfirmSignUp(confirmSignUpRequest).continueWith { task -> AnyObject? in
DispatchQueue.main.async {
if let error = task.error {
print("Confirmation Error: \(error)")
// Handle confirmation error
} else {
print("User Confirmed")
// User is confirmed, proceed with login or next steps
}
}
return nil
}
}
This of course wouldn't be implemented in production code. For dev only.