Mastering AWS Cognito: The Ultimate Guide to User Attributes
Tags: aws, cognito, javascript, node
Published: 2023-09-07 22:20:30

Ah, AWS Cognito! The managed authentication provider that promises a smooth sailing journey, but occasionally feels more like you're navigating the Bermuda Triangle. 

If you're a developer wading through the Cognito waters, you might relate to the urge to use your keyboard as a frisbee.

Here's a glimpse into my roller-coaster ride with AWS Cognito, and how I made it through.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x0029mcz15bx7jnfzdbr.jpg)

## Prologue: The Simple Path Often Forgotten

Before we venture into the murky waters, here's a golden nugget of advice: Always store the Cognito Username (which is essentially the Cognito ID) whenever you create or fetch a user. This unassuming string can be your magical key to bypass a lot of headaches. With this, updating user attributes is straightforward:

```typescript
async function directUpdateUsingUsername(username: string, attributes: any) {
    await cognito.adminUpdateUserAttributes({
        UserPoolId: process.env.COGNITO_USER_POOL_ID,
        Username: username,
        UserAttributes: attributes
    });
}
```

On the frontend, you can easily get this using getCurrentUser. Keep this in your arsenal.


## 1. The Basics: Updating User Attributes

Setting user attributes in Cognito without knowing it's username is like trying to convince a cat to take a bath. It's possible, but be prepared for some resistance.

```typescript
import { CognitoIdentityProvider } from "@aws-sdk/client-cognito-identity-provider";

const cognito = new CognitoIdentityProvider({
    region: process.env.AWS_REGION
});

async function updateUserAttributes(username: string, attributes: any) {
    await cognito.adminUpdateUserAttributes({
        UserPoolId: process.env.COGNITO_USER_POOL_ID,
        Username: username,
        UserAttributes: attributes
    });
}
```

**Note:** Remember to handle any errors gracefully. Cognito can be... prickly.


## 2. Finding Nemo: Search by Email (or other standard attributes)


You may not know a user's Cognito ID, but you might have their email! Here's how you embark on your quest to find them:


```typescript
async function findUserByEmail(email: string) {
    const users = await cognito.listUsers({
        UserPoolId: process.env.COGNITO_USER_POOL_ID,
        Filter: `email = "${email}"`,
        Limit: 1
    });

    if (users && users.Users && users.Users.length > 0) {
        return users.Users[0];
    }
    throw new Error("User not found!");
}
```

## 3. The Disappointment: Custom Attributes Aren't Searchable! 😭

One might think, "Oh, I have this custom:unicornAttribute. I can just search by that!" But no, Cognito thwarts us once again. Thought you could search by custom:myFavoriteColor? Cognito laughs at our naive optimism. Custom attributes are like the secret menu at your favorite cafe: they exist, but you can't just order from them directly.


## 4. Iterative Search: When All Else Fails...

If you're desperate to find a user by a custom attribute, there's an (inefficient) way: List all users and search them client-side. (Do this only if you're feeling brave and have and now other way)


```typescript
async function findUserByCustomAttribute(attributeName: string, value: string) {
    let paginationToken;
    do {
        const result = await cognito.listUsers({
            UserPoolId: process.env.COGNITO_USER_POOL_ID,
            PaginationToken: paginationToken
        });

        for (const user of result.Users) {
            for (const attr of user.Attributes) {
                if (attr.Name === attributeName && attr.Value === value) {
                    return user;
                }
            }
        }

        paginationToken = result.PaginationToken;
    } while (paginationToken);

    throw new Error("User not found!");
}
```

### In Conclusion:

AWS Cognito, with its quirks and idiosyncrasies, can be a beast to tame. But with a sprinkle of patience, a dash of humor, and maybe a glass of wine (or two), you can conquer it!