Is it possible to modify AWS Cognito user attributes in the Lambda triggers

aws cognito edit user attributes
aws cognito lambda trigger example
aws lambda cognito authentication
cognito pre authentication trigger
aws sdk cognito
cognito get user attributes
cognito change email
post confirmation lambda cognito example

Having a look at the AWS documentation,

https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-pre-signup

you have the following paramaters available in the Pre Sign-up Lambda fuction:

"request": {
  "userAttributes": {
    "string": "string",
    ....
},
"validationData": {<validation data as key-value (String, String) pairs, from the client>}

is there a way to modify or add additional userAttributes the the event object?

for example:

// Modify an existing username...
event.request.userAttributes.name.ucfirst();

// Add an additional attribute...
event.request.userAttributes.nickname = "ANY_NAME";


callback(null, event);

Yes, there's absolutely a way! You need to use AWS javascript SDK in your Lambda handler:

const AWS = require('aws-sdk');
AWS.config.update({region: 'ap-southeast-1'});

const cognitoidentityserviceprovider =
  new AWS.CognitoIdentityServiceProvider({
    apiVersion: '2016-04-18'
  });
cognitoidentityserviceprovider.adminUpdateUserAttributes(
  {
    UserAttributes: [
      {
        Name: 'YOUR_USER_ATTRIBUTE_NAME',
        Value: 'YOUR_USER_ATTRIBUTE_VALUE'
      }
    ],
    UserPoolId: event.userPoolId,
    Username: event.userName
  },
  function(err, data) {
    ...
  }
);

Make sure to give your Lambda function the right policies (i.e. allows "cognito-idp:AdminUpdateUserAttributes" action) and the user pool has the attribute defined.

You can use AWS Lambda triggers to customize workflows and the user experience with Amazon Cognito. You can create the following Lambda triggers: Pre  You can't change standard user pool attributes after a user pool is created. Instead, create a new user pool with the attributes that you want to require for user registration. Then, migrate existing users to the new user pool by using an AWS Lambda function as a user migration trigger.

There isn't a way to mutate/augment attributes during sign up, but during sign in, you can mutate/augment them with the pre-token generation trigger.

Custom Message Request Parameters. userAttributes. One or more name-value pairs representing user attributes. codeParameter. A string for  Customizing User Pool Workflows with Lambda Triggers You can create an AWS Lambda function and then trigger that function during user pool operations such as user sign-up, confirmation, and sign-in (authentication) with a Lambda trigger.

For anyone else looking into insight on this question, here is an example below

The lambda function #1 below takes into two custom attributes ida and ethaddress. The lambda is invoked during the PreSignUpHook for Cognito user pools

#2 (Before event changed logs) the original values for these attributes is ida=1 and ethaddress=ABCD

#3 (After event changed logs) reflects the changed values of these attributes: ida=2 and ethaddress=EFGH

However the values which are saved to cognito are the original ones: ida=1 and ethaddress=ABCD. Therefore updateing the userAttributes during the presignuphook does NOT work as suggested in some of the answers.

On a side note when the predefined attributes in the response object are modified they are updated as expected:

"response": {
    "autoConfirmUser": true,
    "autoVerifyEmail": false,
    "autoVerifyPhone": false
}
1. LAMBDA:
'use strict';
global.fetch = require('node-fetch')

module.exports.preSignUp = async (event, context, callback) => {
// Set the user pool autoConfirmUser flag after validating the email domain

let data = await fetch("http://***.***.***/api/members/create",
{
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    method: "POST",
})
.then(res => res.json())
.then(res => res);

event.response.autoConfirmUser = true;
console.log('before event:', JSON.stringify(event)); 
event.request.userAttributes['custom:ethaddress'] = String(data.address); 
event.request.userAttributes['custom:ida'] = "2";  
console.log('Received event:', JSON.stringify(event));  
console.log('Address:', data.address);


 // Return to Amazon Cognito
callback(null, event);
 };
2.

BEFORE EVENT CHANGE LOG:

2019-01-20T01:02:24.639Z    edce636e-75ea-492b-b6a0-dd4f22dc9038    before event:
{
    "version": "1",
    "region": "us-east-1",
    "userPoolId": "us-east-1-*****",
    "userName": "*******@gmail.com",
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "******************"
    },
    "triggerSource": "PreSignUp_SignUp",
    "request": {
        "userAttributes": {
            "custom:ida": "1",
            "custom:ethaddress": "ABCD",
            "email": "*******@gmail.com"
        },
        "validationData": {}
    },
    "response": {
        "autoConfirmUser": true,
        "autoVerifyEmail": false,
        "autoVerifyPhone": false
    }
}
3 .

AFTER EVENT CHANGE LOG:

Received event:
{
    "version": "1",
    "region": "us-east-1",
    "userPoolId": "us-east-1_0BaE6eaTY",
    "userName": "*******@gmail.com",
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "*****************"
    },
    "triggerSource": "PreSignUp_SignUp",
    "request": {
        "userAttributes": {
            "custom:ida": "2",
            "custom:ethaddress": "EFGH",
            "email": "*******@gmail.com"
        },
        "validationData": {}
    },
    "response": {
        "autoConfirmUser": true,
        "autoVerifyEmail": false,
        "autoVerifyPhone": false
    }
}

UPDATE:

It seems like there is no way to do this as a part of the PRESIGNUP process However it is possible to do this as a POSTCONFIRMATION trigger in cognito example provided below.

Some things to watch out for.

  1. the custom attribute has added in cognito and is mutable.
  2. in App client --> show details --> "Set attribute read and write permission" Ensure there is below read and write perms on the custom attribute.
  3. Ensure that the lambda function has a ROLE which allows it to execute: adminUpdateUserAttributes E.g. Attach AmazonCognitoPowerUser Policy to the LambaRole.
module.exports.postConfirmation = async (event, context,callback) => {
        const cognitoIdServiceProvider = new CognitoIdentityServiceProvider({
          region: 'us-east-1'
        });

        var params =  {
            UserAttributes: [
              {
                  Name: 'custom:sillyName',
                  Value: 'customSillyName'
              }
            ],
            UserPoolId: event.userPoolId,
            Username: event.userName
        }

        cognitoIdServiceProvider.adminUpdateUserAttributes(params, function(err, data) {
          if (err) console.log(err, err.stack); // an error occurred
          else     console.log(data);           // successful response
        }); 

        callback(null,event);

};

Note if you attempt to user cognitoIdServiceProvider.adminUpdateUserAttributes in the preSignUp trigger hook you;ll get an exception saying the user does not exit yet

For details on the authentication flow with the user migration Lambda trigger see If this attribute is set to RESET_REQUIRED, the user is required to change his or her The previous user will no longer be able to log in using that alias. Kindle. Amazon Cognito invokes this trigger when a user does not exist in the user pool at the time of sign-in with a password, or in the forgot-password flow. After the Lambda function returns successfully, Amazon Cognito creates the user in the user pool. For details on the authentication flow with the user migration Lambda trigger see Importing Users into User Pools With a User Migration Lambda Trigger .

Well, the simple solution would be like so, adding this to the "Pre Sign-up Lambda function", taking cue from your code:

// Modify an existing username...
 event['request']['userAttributes']['name'] = "My_NAME";

// Add an additional attribute...
 event['request']['userAttributes']['custom:sillyname'] = "ANY_NAME";

 callback(null, event);

Considering you have added the custom:sillyname attribute for the user pool.

Otherwise an error will occur and the user will not be able to complete sign-up. If the email attribute is selected as an alias, an alias will be created for the user's  Amazon Cognito does not store the ClientMetadata value. This data is available only to AWS Lambda triggers that are assigned to a user pool to support custom workflows. If your user pool configuration does not include triggers, the ClientMetadata parameter serves no purpose. Amazon Cognito does not validate the ClientMetadata value.

In addition to updating user attributes, this API can also be used to mark You create custom workflows by assigning AWS Lambda functions to user pool triggers. User Pool Workflows with Lambda Triggers in the Amazon Cognito This exception is thrown when Amazon Cognito is not allowed to use your email identity. def lambda_handler(event, context): if event['callerContext']['clientId'] == "<user pool app client id to be blocked>": raise Exception("Cannot authenticate users from this user pool app client") # Return to Amazon Cognito return event. Amazon Cognito passes event information to your Lambda function.

In addition to updating user attributes, this API can also be used to mark User Pool Workflows with Lambda Triggers in the Amazon Cognito Developer Guide . It is not possible to pass arbitrary binary values using a JSON-provided value  This can be done by using the AdminUpdateUserAttributes API or the admin-update-user-attributes CLI command to change the phone_number_verified attribute to true. Important Phone numbers must follow these formatting rules: A phone number must start with a plus ( + ) sign, followed immediately by the country code.

For your information I can get custom attribute using the aws cli. with the command: aws cognito-idp admin-get-user --user-pool-id xxxxxxxx --username xxxxxxxx. But it is impossible with aws-android-sdk to get custom attributes info using cognitoUserDetails getAttributes().

Comments
  • Hello @dieheld, Have you found solution for this problem?
  • I ran into the same question. I looks like there is no way to modify the user attributes except for the three - event.response.autoConfirmUser, event.response.autoVerifyEmail, and event.response.autoVerifyPhone which can be done in Pre Signup, but none of the custom: ones can be modified. None of the trigger hooks support updating custom: user attributes afaik and based on my tests. This could be a highly desirable feature.
  • This doesn't work for me within the Pre-signup function; it looks like the user isn't created at this point. Did anyone else get it to work?
  • I suspect this is the correct answer, because none of the other solutions work for me.
  • Does it work for SAML identity provider as well? I have noticed that, changes in the SAMLResponse attributes, doesnt update the user attribute in user pool.
  • Nope. I have tested both Pre Signup and Post Confirmation triggers and in both cases the error message is "errorMessage": "User does not exist." At both of these stages, the user apparently is still not created in the pool because of which the attributes can't be updated using the SDK APIs. Injecting updated Attributes to event.request.userAttributes in pre signup trigger also doesn't seem to work. The only thing that can be done is validation type stuff and other things like logging etc.
  • Or use event.request.userAttributes['custom:sillyname'] = "ANY_NAME" ;
  • When I try this, I get a failure of "InvalidLambdaResponseException"; can you confirm that this functions correctly?
  • Which trigger are you using the lambda function in ?
  • @Shaw this was probably because you has a return statement toward the end of your function instead of just invoking the call back.
  • I'm pretty sure you can't do this in the Pre Sign-Up Lambda as the user does not exist yet. At least in my testing I've never been able to get this to work at this phase.