amplify-js icon indicating copy to clipboard operation
amplify-js copied to clipboard

Cognito Analytics are not being sent to Pinpoint when using Authenticator

Open ivan-kiselev opened this issue 2 years ago • 10 comments

Before creating a new issue, please confirm:

On which framework/platform are you having an issue?

React

Which UI component?

Authenticator

How is your app built?

Create React App

What browsers are you seeing the problem on?

Firefox, Safari

Which region are you seeing the problem in?

eu-central-1, us-east-1

Please describe your bug.

User SignUp analytics don't show up in the PinpointAnalytics when using AWS Amplify Authenticator with configured Analytics block:

Amplify.configure({
  Analytics: {
    Pinpoint: {
      bufferSize: 100,
      flushInterval: 30,
      flushSize: 100,
      resendLimit: 10,
      appId: "MY_ID",
      region: "eu-central-1",
    },
  },
  Auth: {
    Cognito: {
      userPoolClientId: "MY_ID",
      userPoolId: "MY_ID",
      signUpVerificationMethod: "link",
      loginWith: {
        username: true,
        email: true,
        phone: false,
      },
    },
  },
});

User sign up is performed successfully, the integration between the AWS Cognito and pinpoint analytics is configured in the console:

Screenshot 2024-01-21 at 16 28 38

What's the expected behaviour?

When I sign up in my App, I want to see some activity in integrated with my Cognito client pinpoint project, but nothing happens.

Documentation states that SignUp event from cognito shall be reflected, though it also mentions vaguely that request should "include an AnalyticsEndpointId value in the AnalyticsMetadata parameter of your API request", which I don't see happening if I inspect requests to Cognito from my UI when I press "sign up" button on Authenticator component. I only see essential for registration data: Screenshot 2024-01-21 at 16 35 37

Help us reproduce the bug!

Set up cognito user pool, cognito client and integrate the client with pinpoint analytics.

Use this client for web-interface based on the following snippet

Code Snippet

// Put your code below this line.
Amplify.configure({
  Analytics: {
    Pinpoint: {
      bufferSize: 100,
      flushInterval: 30,
      flushSize: 100,
      resendLimit: 10,
      appId: "...",
      region: "eu-central-1",
    },
  },
  Auth: {
    Cognito: {
      userPoolClientId: "...",
      userPoolId: "...",
      signUpVerificationMethod: "link",
      loginWith: {
        username: true,
        email: true,
        phone: false,
      },
    },
  },
});

And Cogntio user pool with a secretless client integrated with Pinpoint app in the same region, and authenticator:

        <Authenticator signUpAttributes={["email"]}>
          {({ signOut, user }) => (
            <View>
              <Heading color="pieCrust.700">Hello {user?.username}</Heading>
              <Text textAlign="center">Welcome to our application!</Text>
              <Button onClick={signOut}>Sign out</Button>
            </View>
          )}
        </Authenticator>

Console log output

No response

Additional information and screenshots

I generally see AnalyticsMetadata in the corresponding library, but I am not sure if I need to do something additionally myself to make the client propagate this field.

I am not really good with frontend, trying me best here, sorry if I am missing something absolutely obvious.

ivan-kiselev avatar Jan 21 '24 15:01 ivan-kiselev

@ivan-kiselev Going to transfer this issue over to our sibling team Amplify JS to see if they can unblock you with the Pinpoint/Cognito integration piece as analytic recording is not handled by the Authenticator without customization

@cwomack Based on the provided info above (see cognito docs) is this something we can help with?

calebpollman avatar Jan 23 '24 01:01 calebpollman

So, the only way to get analytics propagated to the pinpoint I've found, is to use low-level AWS APIs, like so:

import { Amplify, ResourcesConfig } from "aws-amplify";
import {
  AuthFlowType,
  CognitoIdentityProviderClient,
  InitiateAuthCommand,
} from "@aws-sdk/client-cognito-identity-provider";

const rawPasswordSignIn = async (
  username: string,
  password: string,
  config: ResourcesConfig
) => {
  const client = new CognitoIdentityProviderClient({
    region: config.Analytics?.Pinpoint?.region,
  });
  const input = {
    ClientId: config.Auth?.Cognito?.userPoolClientId,
    AuthFlow: AuthFlowType.USER_PASSWORD_AUTH,
    AuthParameters: {
      USERNAME: username,
      PASSWORD: password,
    },

    AnalyticsMetadata: {
      AnalyticsEndpointId: config.Analytics?.Pinpoint?.appId,
    },
  };
  const command = new InitiateAuthCommand(input);
  return await client.send(command);
};

And I see all the JWT tokens successfully returned, the Auth, Refresh and ID tokens. Now.. I either have to implement my own auth provider, or feed these tokens in a tricky way somehow to the auth provider of Amplify. I presume, the latter is not recommended, right?

I guess I could write cookies with the same names as Amplify would expect? But something would've gone wrong for sure anyways. So I guess my best shot is to wait until analytics are implemented natively in Amplify library and until then implementing authentication logic myself?

ivan-kiselev avatar Jan 23 '24 19:01 ivan-kiselev

Ok, so I thought I am going to be smart and do the following:

import { record } from "@aws-amplify/analytics";
import { signIn } from "@aws-amplify/auth";

  const handleSignIn = async () => {
      const response = await signIn({ username, password });
      record({
        name: "_userauth.sign_in",
        attributes: {
          CognitoClientId: `(web) ${config.Auth?.Cognito?.userPoolClientId}`,
        },
      });
      flushEvents();
      console.log(response);
  };

E.g. use amplify function for sign-in operation so it propagates all the cookies and what not to the wrapping Authenticator.Provider provider and then record the event in analytics manually, imitating the way it'd be done by Cognito, but it's troublesome and totally not the same.

record call finishes in the warning:

Screenshot 2024-01-24 at 10 11 13

And indeed if one exercises fetchAuthSession from @aws-amplify/auth, it will yield empty credentials even after successful signIn with all the cookies present, so I guess it's just not the same to first signin/signup and then send an analytics event separately, especially considering that AnalyticsMetadata is straight up a field for the SignUp Cognito request and this analytics events are supposedly coming from Cognito and not client.

So yeah. The only way to do that properly is to have it handled in amplify libs themselves.

@cwomack any chances it could be an easy fix?

ivan-kiselev avatar Jan 24 '24 09:01 ivan-kiselev

Hey @reesscot @nadetastic @cwomack The PR is ready for initial review, I haven't updated docs presuming there are going to be corrections to the PR, I will do so shall changes be approved.

Would appreciate if you could give it a look!

ivan-kiselev avatar Jan 25 '24 10:01 ivan-kiselev

Hi @ivan-kiselev thank you for your contribution!

I've been taking a look at this issue to better understand and validate the problem, but I believe that as long as your user pool client is connected to Pinpoint it should automatically send the events without additional config since under the hood the library will invoke the supported API actions such as InitiateAuth for signIn.

I will follow up soon with an update and also further discuss with the team. Let me know if you have any additional question in the meantime.

nadetastic avatar Jan 25 '24 17:01 nadetastic

@ivan-kiselev follow up question. It looks like you manually created the Cognito and Pinpoint resource without the Amplify CLI - in that case, what may be missing are the permissions needed by Cognito Identity pool roles to be able to send events to Pinpoint.

Have you had a chance to review this related issue/comment?

https://github.com/aws-amplify/amplify-js/issues/9131

nadetastic avatar Jan 25 '24 17:01 nadetastic

I believe that as long as your user pool client is connected to Pinpoint it should automatically send the events without additional config since under the hood the library will invoke the supported API actions such as InitiateAuth for signIn.

That's not entirely true. From the very same documentation page that you mentioned:

To pass metadata about your user's session to your Amazon Pinpoint campaign, include an AnalyticsEndpointId value in the AnalyticsMetadata parameter of your API request

In other words, Cognito <=> Pinpoint analytics works in such a way that if your requests to Cognito don't include appropriate AnalyticsMetadata, your analytics events won't make it to Pinpoint, and I can confirm it from my experience. That's why I opened this issue to begin with.

The linked PR introduces this to the code, enriching requests with analytics metadata shall it be present on the top level config.

what may be missing are the permissions needed by Cognito Identity pool roles to be able to send events to Pinpoint.

I believe the author of the linked issue had the same problem, but the person replying got confused (fairly so) a bit and addressed different, though seemingly similar problem.

From the perspective of current github issue and the one you linked, there are two distinct sources of events for Pinpoint analytics:

  • Events that are coming to Pinpoint from web applications (e.g. when user directly calls record({...}) from @aws-amplify/analytics. E.g. Chain of interaction is Web Client => AWS Pinpoint.
  • Events that are coming to Pinpoint from Cognito when user authorizes. E.g. Chain of interaction is Web Client => AWS Cognito => AWS Pinpoint.

So, what you are referring to, is the first case, when Web Client directly sends events to the Pinpoint, and the comment you linked is legit for that case.

What current Issue and corresponding PR are about, is the second case, when User interacts with Cognito, and Cognito, in turn, sends analytical events to Pinpoint.

Now, about permissions. I do believe one doesn't need to create/associate their own IAM permissions for the case I am talking about. As a proof, try to associate Pinpoint project with a Cognito Client through UI, you will see the following (read the Permission to access Amazon Pinpoint section).

Screenshot 2024-01-26 at 12 37 04

Same with terraform, if you try to just run this, without creating any special permissions or roles, AWS will work it's magic and create trust relationships between cognito-idp service and standard role that has required permissions:

resource "aws_cognito_user_pool_client" "web" {
  name                          = "web"
...
  // Must be configured through ARN, otherwise it gets misconfigured, see
  // https://github.com/hashicorp/terraform-provider-aws/issues/35418
  analytics_configuration {
    application_arn  = aws_pinpoint_app.authentication_activity.arn
    user_data_shared = true
  }
}

resource "aws_pinpoint_app" "authentication_activity" {
  name = "authentication_activity"
}

With the configuration above, Cognito-related events start popping up in pinpoint without any additional configuration (but be patient if you are going to test it, it might take up to 15 minutes between sign up is triggered/confirmed and it appears in Pinpoint, it's very async)

Does this address your concern?

@nadetastic

ivan-kiselev avatar Jan 26 '24 11:01 ivan-kiselev

@nadetastic Friendly ping here

I'd need to decide whether to stick to Amplify for the long term in the project or implement everything myself, and analytics integration between cognito and pinpoint not being implemented on Amplify side is one of the decision factors.

ivan-kiselev avatar Jan 30 '24 17:01 ivan-kiselev

Hi @ivan-kiselev thank you for you patience, and for clearing this issue up for me, as well as your contribution for addressing this use case! I've discussed this with the team and we are currently reviewing the PR you submitted - will follow up on it soon with any additional feedback. But in the meantime let me know if you have any additional comment/questions - I'll also make sure to provide an update again soon.

nadetastic avatar Jan 31 '24 20:01 nadetastic

@nadetastic thanks, looking forward!

ivan-kiselev avatar Feb 01 '24 13:02 ivan-kiselev

Closing due to inactivity

ivan-kiselev avatar May 31 '24 10:05 ivan-kiselev