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

Authenticated graphql requests with SSR missing custom attributes

Open asp3 opened this issue 4 years ago • 3 comments

Describe the bug We have recently switched to using SSR with Next.js, and we have been trying to modify some of our api calls to be able to be used with server side rendering. However, we ran into an issue because in our backend, we use the identity.claims in an appsync call to determine the identity of a user and get some of their common attributes, but when using API.graphql from withSSRContext, it looks like those fields were omitted. We believe this is because the type of authentication is token_use: access instead of token_use: id, but looking through the docs there does not seem to be a good way to change our server side calls to use the ID Token.

Expected behavior As you can see below, when an auth is made by initializing a graphql client on client side , there is extra information in identity.claims such as Name, referral, classInfo, etc. However, when the same API call is made using API.graphql() using const { API } = withSSRContext(context), the identity.claims has the generic values. When calling Auth.currentAuthenticatedUser in both SSR and on client side, the payload returns correctly, and all of the added values are visible in the payload (user.signInUserSession.idToken.payload).

Code Snippet

API call made from client side

"identity": {
    "claims": {
      "sub": "...",
      "access_pool": "0",
      "cognito:groups": [
        "Teachers"
      ],
      "email_verified": true,
      "iss": "...",
      "cognito:username": "...",
      "aud": "...",
      "referral": "...",
      "classinfo": "...",
      "token_use": "id",
      "auth_time": 1595474525,
      "name": "...",
      "ID": "...",
      "exp": 1595478125,
      "iat": 1595474525,
      "access_pool_expiry": "0",
      "email": "..."
    },
    "defaultAuthStrategy": "ALLOW",
    "groups": [
      "Teachers"
    ],
    "issuer": "...",
    "sourceIp": [
      "..."
    ],
    "sub": "...",
    "username": "..."
  },

API Call made from SSR

  "identity": {
    "claims": {
      "sub": "...",
      "device_key": "...",
      "cognito:groups": [
        "Teachers"
      ],
      "token_use": "access",
      "scope": "aws.cognito.signin.user.admin",
      "auth_time": 1614323009,
      "iss": "...",
      "exp": 1614326991,
      "iat": 1614323391,
      "jti": "...",
      "client_id": "...",
      "username": "..."
    },
    "defaultAuthStrategy": "ALLOW",
    "groups": [
      "Teachers"
    ],
    "issuer": "...",
    "sourceIp": [
      "..."
    ],
    "sub": "...",
    "username": "..."
  },

asp3 avatar Feb 26 '21 08:02 asp3

Any update on this? Seems like you are currently unable to use email as the identityClaim using Next JS

jarrodwatts avatar May 17 '21 04:05 jarrodwatts

Can you share more code on how to reproduce or see this behavior? For starters, it sounds like Auth. currentAuthenticatedUser() is correct on both client & server, but API.graphql is missing email. How could I reproduce & see that?

There's been testing to validate that Auth & API work as expected with SSR, but it seems like there's more nuanced behavior that hasn't been validated.

ericclemmons avatar May 19 '21 17:05 ericclemmons

Hey @ericclemmons I'll post what code I was using to encounter the error.

So I was using the following code for Amplify.configure:

Amplify.configure({
  ...awsconfig,
  // https://github.com/aws-amplify/amplify-cli/issues/3794
  graphql_headers: async () => {
    try {
      const token = (await Auth.currentSession()).idToken.jwtToken;
      return { Authorization: token };
    } catch (e) {
      console.error(e);
      return {};
    }
  },
  ssr: true,
});

and then for example, in one of my dynamic route pages, I have this code for getServersideProps:

export const getServerSideProps: GetServerSideProps = async (context) => {
  const { req } = context;
  const SSR = withSSRContext({ req });

  const input: GetBoardQueryVariables = {
    id: context?.params?.id as string,
  };

  const response = (await SSR.API.graphql({
    query: getBoard,
    variables: input,
    authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS,
  })) as { data: GetBoardQuery; errors: any[] };

  return {
    props: {
      board: response.data.getBoard,
    },
  };
};

IIRC, the error was "No current user" in the console.error, inside the catch of the Amplify.configure.

The getServersideProps code worked fine until I modified the graphql_headers to try and use email for identityClaim.

When I changed that graphql_headers though, it stopped working, saying No current user on the server-side.

For now, I've just made all my authenticated requests client-side - which isn't that big of a deal for my project.

Let me know if you need any more information.

I have a repo for this code if that would be more helpful. The two pages can be found here: Note you might need to be on the multi-user branch _app.tsx /board/[id].tsx - The commented out section at the bottom does not work with my setup.

jarrodwatts avatar May 22 '21 02:05 jarrodwatts

Closing this out as we are now on v6 of aws-amplify and have been unable to reproduce this issue. If it occurs and is consistently reproducible in v6, please open a new issue with environment info, package versions, and reproduction steps.

chrisbonifacio avatar Mar 27 '24 18:03 chrisbonifacio