User Pool Attributes in AWS Cognito - Complete Guide

avatar

Borislav Hadzhiev

Wed Apr 21 20216 min read

Updated on Wed Apr 21 2021

Cognito User Attributes allow us to store information on the User object, that we can then use throughout our application code.

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's not included in the default provided cognito ones, you have to use a custom attribute, i.e. add a boolean isAdmin 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.

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

cd aws-cognito-user-attributes && npm install
  1. Deploy the stack
npm run cdk-create-stack
  1. Your stack has been deployed to your default profile 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 CLI 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 / 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 / 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, meaning these 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, with 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 console still on the Attributes tab 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 have 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 / 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 specified the family name and given name attribute as required in our User Pool, these attributes are always going to be set to writable.

Testing Cognito User Attributes #

Update YOUR_USER_POOL_ID 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 now 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: (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="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.

You could manually delete the User Pool if you'd like.

Conclusion #

We need both default and custom User Pool attributes in order to collect and store user information, i.e. shipping address, country, city and other relevant information that our application use cases require.

The github repository with the CDK code for the creation of the stack is available at: cognito user attributes

Further Reading #

Join my newsletter

I'll send you 1 email a week with links to all of the articles I've written that week

Buy Me A Coffee