Amplify-js: ClientMetadata not passing to Cognito Trigger, with `Auth.signIn({... , validationData: {foo: 'bar'}})`

Created on 5 Sep 2020  路  18Comments  路  Source: aws-amplify/amplify-js

Describe the bug
ClientMetadata not passing to Cognito Trigger, when using Amplify Custom Ui components and Auth.signIn()
Auth.signIn({... , validationData: {foo: 'bar'}}), even with static preconfigured ClientMetadata,
Auth.configure({ authenticationFlowType: 'CUSTOM_AUTH', clientMetadata: {foo: 'bar'} }) or
Amplify.configure({ Auth: { authenticationFlowType: 'CUSTOM_AUTH', clientMetadata: {foo: 'bar'} } })

To Reproduce
Steps to reproduce the behavior:

browser js code

Auth.configure({ clientMetadata: {foo: 'bar'}  })
await Auth.signIn({ username: 'someuser', validationData: {xyz: 'abc'} })

lambda trigger

exports.handler = (event, ctx, callback) => {
  console.log(event)
}

Expected behavior

Expect to see log of foo , xyz ClientMetadata in lambda cloudwatch logs , this are missing.

Additional context
Amplify versions

  • "aws-amplify": "^3.1.1",
  • "aws-amplify-react": "^4.2.2",

_You can turn on the debug mode to provide more info for us by setting window.LOG_LEVEL = 'DEBUG'; in your app._

browser_debug_log

Screenshot_20200905_014143 (1)

cloudwatch log*

2020-09-04T22:19:05.727Z    ****    INFO    {
  version: '1',
  region: 'us-west-2',
  userPoolId: '****',
  userName: '****',
  callerContext: {
    awsSdkVersion: 'aws-sdk-unknown-unknown',
    clientId: '****'
  },
  triggerSource: 'DefineAuthChallenge_Authentication',
  request: {
    userAttributes: {
      sub: '****',
      email_verified: 'true',
      'cognito:user_status': 'CONFIRMED',
      'cognito:email_alias': '****',
      given_name: '****',
      family_name: '****',
      email: '****'
    },
    session: [],
    userNotFound: false
  },
  response: { challengeName: null, issueTokens: null, failAuthentication: null }
}

Auth React Service Team bug

Most helpful comment

@sammartinez, thanks for getting back to us on this issue. Do you have any idea when this may be resolved? We are in the progress of rewriting our authentication backend, but if this is resolved within a reasonable timeframe we will skip that rewrite.

The main thing for us is that the clientMetadata should be made available in all the available Cognito lambda triggers. It is also important that if the clientMetadata has been set during Auth.signIn in the js client, it should be set automatically if the Auth framework does an automatic refresh.

All 18 comments

Hi, any update on this?

clientMetadata is not received in lambda at all on second and subsequent call to Auth.signIn.. this is really a deal breaker for us.

I've been trying work arounds like calling signOut first, etc but to no avail..

This really needs to be prioritized. This nearly caused our production users to be able to see each others data!!!

@jordanranz Is it possible to get some help with this?

@obonyojimmy Apologizes on the late response to this. Are you configuring the Lambda triggers via our Amplify CLI? I want to make sure this issue gets routed to the correct location so please let me know. Thanks ahead of time

Hi @sammartinez , thanks for reply , the lambda triggers are not configured using Amplify Cli , but manually from Cognito console page.

@obonyojimmy Apologizes on the late response to this. Are you configuring the Lambda triggers via our Amplify CLI? I want to make sure this issue gets routed to the correct location so please let me know. Thanks ahead of time

@sammartinez i did configure via Amplify CLI - and im having the same problem.

@sammartinez:

Please see my original SO question mentioned by @obonyojimmy: https://stackoverflow.com/questions/62548852/aws-cognito-and-amplify-clientmetadata-not-sent-when-session-is-refreshed

This is how it works in our current implementation: it is possible to set a clientMetadata object in the Auth.signIn request, like this:

Auth.signIn(auth.email, auth.password, {"metadataKey1": "metadataValue1"})
    .then(response => {
        // Sign in OK
    })
    .catch(error => {
        // Something went wrong
    });

In our manually configured lambda triggers, we can read this metadata from two trigger points: Pre authentication and Pre Token Generation. In the Pre authentication trigger, it can be read from request.validationData. In the Pre Token Generation trigger, it can be read from request.clientMetadata.

Problem 1: we see that during the Auth.signIn process, the Amplify library automatically does a session refresh where the clientMetadata object is not included. I have not found a way how to make sure it gets set.

Problem 2: when we do a manual session refresh, by calling Auth.currentAuthenticatedUser() and then doing a user.refreshSession call, it is possible to send a clientMetadata object but it is not possible to read it in the Pre Token Generation trigger.

What we expect: if it is possible to set a clientMetadata object during Auth.signIn, the same clientMetadata object should be sent with the automatic session refresh and it should also be possible to send the clientMetadata when manually refreshing the user session.

The docs here also say you can pass validationData/clientMetadata to Auth.signUp, but that doesn't appear to be the case when looking at the function definitions.

I've gotten the validationData to show up in event.request, but only in the migrate user lambda trigger. I have not been successful in passing clientMetadata to any lambda trigger.

This is pretty limiting, and I need it for several use cases as we migrate our users into Cognito.

It's not clear to me if this is entirely an Amplify bug or Cognito limitations, at this point. For example, careful reading of the Cognito docs, along with some googling, indicates that clientMetaData is never passed to the "Define Auth Challenge" trigger for some unstated reason. However, clientMetadata _should_ be available in the "Create Auth Challenge" and "Verify Auth Challenge" triggers, but I've had no luck getting it to work with Amplify.

At this point, I'm considering abandoning Amplify and just using the aws-sdk. Not sure the benefits of Amplify outweigh the limitations.

@jcowley I can see the web request to the Cognito endpoint does have clientMetadata defined, so I'm not sure whether the Cognito docs are just wrong or if it's a Cognito bug.

Either way, not being able to manipulate claims in the access token, and not having client metadata in the preTokenGeneration hook make Cognito useless for anything other than the most basic auth flows.

+1. I decided to use Cognito only for authentication and lambdas for authorization. Works for us and we won't wait for quite a while to get this one fixed.

Thanks for your feedback and patience on this issue. We have identified the issue and we are talking to the Amazon Cognito team internally about this. We will provide an update once we have one.

@sammartinez, thanks for getting back to us on this issue. Do you have any idea when this may be resolved? We are in the progress of rewriting our authentication backend, but if this is resolved within a reasonable timeframe we will skip that rewrite.

The main thing for us is that the clientMetadata should be made available in all the available Cognito lambda triggers. It is also important that if the clientMetadata has been set during Auth.signIn in the js client, it should be set automatically if the Auth framework does an automatic refresh.

I have a working code snippet to pass data as parameter to the lambda function with Cognito Pre authentication trigger:

await Auth.signIn({
    username: username,
    password: password,
    validationData: {
        metaDataKey: "metaDataValue"
    }
});

You can fetch the passed data value from "event.request.validationData.metaDataKey" on the Lambda side (Node.js).

An example for email validation to check if email unconfirmed or not:
Client-side:

await Auth.signIn({
    username: username,
    password: password,
    validationData: {
        email: email
    }
});

Lambda function (Node.js):

var AWS = require('aws-sdk');

exports.handler = async (event, context, callback) => {
    console.log("Received event");
    console.log(event);
    var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider({
        apiVersion: "2016-04-18",
        region: event.region
    });
    let params = {
        UserPoolId: event.userPoolId,
        AttributesToGet: ["email"],
        Filter: "email='"+event.request.validationData.email+"'"
    };

    try {
        let response = await cognitoidentityserviceprovider.listUsers(params).promise();
        console.log(response);
        let users = response.Users;
        if (users.length > 0) {
            let user = users[0];
            if (user.UserStatus == "UNCONFIRMED") {
                console.log("user is unconfirmed");
                let customError = new Error("error_user_not_confirmed");
                callback(customError, event);
            }
        }
    }
    catch (e) {
        console.log(e);
    }
    callback(null, event);
};

@sammartinez The following is also supposed to work, but in this case does not pass the clientMetaData to Lambda function as validationData:

await Auth.signIn(username, password, {
    metaDataKey: "metaDataValue"
});

@sammartinez any updates?

This doesn't seem to be an issue with amplify at all. Cognito simply does not support this, regardless of which client library you use. The docs conflict.

  1. This says that clientMetadata is passed to the preTokenGeneration lambda. Analogous pages for other hooks also exist. https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-token-generation.html
  2. The lower-level API reference directly contradicts the reference above with "The ClientMetadata value is passed as input to the functions for only the following triggers: Pre signup, Pre authentication, User migration." https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html

So this should really be brought to the Cognito team's attention. @sammartinez

I can confirm the issue with token refresh. clientMetadata from Auth.configure is not being used for token refresh.

However in case you override clientMetadata when doing Auth.signIn, it seems that should be part of the session as well. I am not 100% sure about that behavior, meanwhile I will send a PR to fix the issue when clientMetadata is used on Auth.configure so at least that use case is covered.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

leantide picture leantide  路  3Comments

benevolentprof picture benevolentprof  路  3Comments

TheRealRed7 picture TheRealRed7  路  3Comments

rygo6 picture rygo6  路  3Comments

guanzo picture guanzo  路  3Comments