User Pool Attributes in AWS Cognito - Complete Guide

avatar

Borislav Hadzhiev

Last updated: Apr 12, 2022

banner

Photo from Unsplash

User Attributes in AWS Cognito #

In this article we will learn how to store default and custom User Pool attributes on cognito Users.

User Pool attributes in AWS Cognito are:

  • standard - the default user attributes you get with every user pool
  • custom - user attributes specific to your application that are not supported by default

Default Attributes are: address, birthdate, email, family_name, gender, given_name, locale, middle_name, name, nickname, phone_number, picture, preferred_username, profile, updated_at, website, zoneinfo - docs.

When you want to store a property on a user that isn't included in the default cognito-provided ones, you have to use a custom attribute, e.g. add a boolean isAdmin attribute to your user.

Initializing the Project #

We will clone a github repository that creates a cognito stack including all the default, and some custom attributes we have defined ourselves.

The code for this article is available on GitHub

This stack creates the following resources in your AWS Account:

  • User Pool
  • User Pool Client
  1. Clone the github repository

  2. Change Directory and install dependencies

shell
cd aws-cognito-user-attributes && npm install
  1. Deploy the stack
shell
npm run cdk-create-stack
  1. The stack has been deployed to your default region. You can check the region in the cdk-exports-dev.json file created in the root directory of the project.

  2. Open the AWS console and click on the cognito-user-attributes-dev stack.

Storing User Attributes in AWS Cognito #

We have created a User Pool and a User Pool Client.

  • The User Pool is the directory where you store and manage your users in AWS Cognito. A User Pool allows your users to register and sign in to your application, and allows you to manage their profiles.

  • The User Pool Client is the part of the User Pool that actually enables unauthenticated operations like register, sign in and forgotten password. You can't call these operations without an app client ID that you get by creating a User Pool Client.

User Pool > General Settings > Attributes

Click on the cognito-user-attributes-dev User pool in the console and select the Attributes property in the left sidebar:

standard attributes required

When creating a User Pool you can set standard attributes as required. This means that the attributes must be provided when a user registers. Note that you can't change the required attributes after creating a user pool.

In our case we have specified the family name and given name standard attributes as required. We did this using the following code in the infra/constructs/user-pool-construct.ts:

infra/constructs/user-pool-construct.ts
this.userPool = new cognito.UserPool(this, 'userpool', { //... rest standardAttributes: { givenName: { required: true, mutable: true, }, familyName: { required: true, mutable: true, }, }, });

Notice how the attributes are set to both required and mutable. The mutable property specifies whether the value of the attribute can be changed. You can't edit the mutable property after creating the attribute.

In the Attributes tab in the console, scroll down to the "Do you want to add custom attributes?" section:

custom attributes

We have set 4 custom attributes: bio, country, city and isAdmin. Note that you can create new custom attributes after User Pool creation, however you can't edit the existing ones.

The code defining the custom attributes is located in the infra/constructs/user-pool-construct.ts file again:

infra/constructs/user-pool-construct.ts
this.userPool = new cognito.UserPool(this, 'userpool', { // ... rest customAttributes: { bio: new cognito.StringAttribute({mutable: true}), country: new cognito.StringAttribute({mutable: true}), city: new cognito.StringAttribute({mutable: true}), isAdmin: new cognito.StringAttribute({mutable: true}), }, });

Note that we set the mutable attribute to true again because we want to be able to change these values.

Notice that all of our custom attributes are of type string. You could say, why would isAdmin be of type string, it should be a boolean.

That would make sense, however the only truly supported type for custom attributes is the string type. If you read the cognito docs they say you can use string or number, if you read the cdk docs they say you can use boolean, datetime, number, string.

However at the time of writing both are wrong and the only truly supported type is string. If you're interested to learn more check out the Custom attributes section of my cognito bugged article

User Pool > General Settings > App clients

Let's move onto the User Pool Client, click on "App clients" in the side bar. The User Pool Client is the part of the User Pool which enables unauthenticated operations like register, sign in and the forgotten password flow.

In the User Pool Client we can set the read and write permissions for our standard and custom attributes.

The section concerning Attributes is "hidden" and a common source of confusion, you have to first click on Show Details:

app client show details

Then you have to scroll to the bottom and click on Set attribute read and write permissions.

The Attributes table will be shown where you can see the read/write permissions for our attributes:

app client show details

Both standard and custom attributes can be marked as readable or writable. An application can only read attributes that are set as readable. If an attribute is not readable it wouldn't be included in the API response.

If an application tries to update an attribute that's not set as writable, you would get a NotAuthorizedException error.

We have set the read attributes in our code in the infra/constructs/user-pool-client-construct.ts file:

infra/constructs/user-pool-client-construct.ts
const clientReadAttributes = new cognito.ClientAttributes() .withStandardAttributes({ givenName: true, familyName: true, email: true, emailVerified: true, address: true, birthdate: true, gender: true, locale: true, middleName: true, fullname: true, nickname: true, phoneNumber: true, phoneNumberVerified: true, profilePicture: true, preferredUsername: true, profilePage: true, timezone: true, lastUpdateTime: true, website: true, }) .withCustomAttributes(...['bio', 'country', 'city', 'isAdmin']);

And the write attributes:

infra/constructs/user-pool-client-construct.ts
const clientWriteAttributes = new cognito.ClientAttributes() .withStandardAttributes({ givenName: true, familyName: true, email: true, // 👇 users can't update their emailVerified attribute emailVerified: false, address: true, birthdate: true, gender: true, locale: true, middleName: true, fullname: true, nickname: true, phoneNumber: true, profilePicture: true, preferredUsername: true, profilePage: true, timezone: true, lastUpdateTime: true, website: true, }) .withCustomAttributes(...['bio', 'country', 'city']);

One difference is the isAdmin property. We don't want users to be able to update this property. Since the property is set as mutable, we can update it using the CLI.

The emailVerified property is also set to false, because we don't want users to be able to verify their email without clicking on the verification link.

Another thing to note is that since we set the family name and given name attributes to required in our User Pool, these attributes are always going to be set to writable.

Testing Cognito User Attributes #

Make sure to update the YOUR_USER_POOL_ID placeholder in the command below.

You can find the user pool id in the cdk-exports-dev.json file in the root directory, or in the General settings tab in the User Pool console.

First, let's create the cognito user:

shell
aws cognito-idp admin-create-user \ --user-pool-id YOUR_USER_POOL_ID \ --username john@example.com \ --user-attributes Name="given_name",Value="john" \ Name="family_name",Value="smith"

User Pool > General Settings > Users and groups

If you now click in the Users and Groups section of your user pool and refresh the page you will see the user we've created.

user john

If you click on the user you will see that we have successfully initialized the user with the given_name and family_name attribute:

user john details

Let's now update some of the other standard (default) user attributes using the CLI (replace your-user-pool-id):

shell
aws cognito-idp admin-update-user-attributes \ --user-pool-id YOUR_USER_POOL_ID \ --username john@example.com \ --user-attributes Name="gender",Value="m" \ Name="name",Value="john smith"

If you're wondering how I got the names of the default attributes, you can find them all in the docs.

If you were to refresh the users page and click on your user, you would see the other standard attributes included into the user profile:

user additional default attributes

Let's update the custom attributes now. Note that when working with custom attributes you have to prefix the attribute name with custom:.

Make sure to replace the YOUR_USER_POOL_ID placeholder with your actual user pool id.

shell
aws cognito-idp admin-update-user-attributes \ --user-pool-id YOUR_USER_POOL_ID \ --username john@example.com \ --user-attributes Name="custom:bio",Value="Loves long walks on the beach" \ Name="custom:country",Value="Chile" \ Name="custom:city",Value="Santiago" \ Name="custom:isAdmin",Value="yes"

If you refresh the page of the user with email john@example.com you would see that our custom attributes have been updated on the user object:

user john custom attributes


Cleanup #

Delete the CDK stack

shell
npm run cdk-destroy

Note that the default behavior for User Pools provisioned via CDK is for them to be retained after stack deletion. However, I've explicitly set the removal policy of this User pool to DESTROY, so it will get deleted when the stack is deleted.

Conclusion #

We need both default and custom User Pool attributes in order to collect and store user information. Common attributes include shipping address, country, city, etc.

The code for this article is available on GitHub

Further Reading #

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.