Auth0 access_token has empty data payload (how to refresh or getTokenSilently or checkSession to reissue a valid JWT) for both AWS and Auth0 auth request access in the same app without double logins?

0

Hi AWS Community,

I seem to have found a conundrum within jwt-based authentication patterns where I need both a jwt to validate two things: (1.) AWS resources via AppSync/Cognito and (2.) Auth0 resources where an access_token with a specific data payload is injected in that jwt as well.

For reference, this is my tech stack:

  • Auth: Amazon Cognito integrated with Auth0 via OpenID Connect (OIDC) as a Federated Identity Provider
  • API: AWS AppSync - includes @auth directives for logged in users which maps back to the above
  • IaC: AWS Amplify CLI
  • Front-End: Next.js (pages router) with TypeScript

In short, from the front-end, when you sign in, Cognito redirects you to the associated Auth0 hosted Login Screen... you log in... and if it's successful, an authorization code is passed back to the your callback URL (the app), and you are authenticated. There seems to be an Auth0 cookie cached as well.

I found this helpful blog post on re:Post [1] which discussed how you can map over the access_token and id_token from Auth0 back into each user with your cognito user pool. However, the issue is that the access_token has an empty body payload and cannot authorize data coming back from Auth0. I came across this dead-end on the Auth0 Community Forum [2] which talked about "Opaque Tokens" where the payload is empty. What I am expecting is an access_token [3]

The issue I seem to have found is that because you cannot pass in an audience key-value pair into Amazon Cognito with a custom scope, that data is "missing" when coming back from Auth0, hence the token isn't decode-able to Auth0. I found out how Amazon Resource Servers can allow you to add in a custom scope [4], but I can't seem to find a way to then actually explicitly state the audience that this additional scope would be relevant for like you can in Postman. This Audience value is important for the Auth0 token-generation scope, so it is required for it [5]

Question 1: Given the need to maintain both access_token's for both authenticating/authorizing both Amazon Cognito user pools resources (i.e. AppSync @auth directives for logged in private users) AND external-to-AWS API calls that require valid Auth0 access_tokens (not id_tokens) with the correct data payload, has anyone figured out how to do this 2nd part with the Auth0 access_token fulfilled?

Question 2: If it is not possible to allow Amazon Cognito to directly call an audience endpoint, is it possible instead to use a pre-token generation lambda script [5] to somehow make a POST request to this endpoint given the user that just logged in and has a valid session? I wonder if it's possible to use Amazon Cognito for the authentication/authorization, and then like an API to call in other data and return that to the user.

Question 3: Is there some client-side wrapper for Next.js that could generate this token instead of needing to do something with Lambda or Amazon Cognito? I found this GitHub issue [7] which seems to be part of this, but I am not sure how to fetch this "session" or "getTokenSilently" if the authorization is scoped to only Amazon Cognito, and nothing else.

Any help would be greatly appreciated!

Thank you!

[1] AWS re:Post: How do I get OIDC or social identity provider–issued tokens after integrating the identity provider with Amazon Cognito?: https://repost.aws/knowledge-center/cognito-user-pool-tokens-issued-by-idp

[2] Auth0 Community Forum: Why is my access token not a JWT? (Opaque Token) https://community.auth0.com/t/why-is-my-access-token-not-a-jwt-opaque-token/31028

[3] Auth0 Docs: Access Tokens: https://auth0.com/docs/secure/tokens/access-tokens

[4] AWS Docs: Defining resource servers for your user pool: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-define-resource-servers.html

[5] Auth0 Community Forum: Understanding how the “audience” concept actually works: https://community.auth0.com/t/understanding-how-the-audience-concept-actually-works/34011

[6] AWS Docs: Pre token generation Lambda trigger: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-token-generation.html

[7] GitHub: nextjs-auth0 — Retrieve access token from the browser?: https://github.com/auth0/nextjs-auth0/issues/358

1 Answer
1
Accepted Answer

This is indeed a complex scenario involving multiple JWTs for different purposes and providers. Here are some potential solutions to your questions:

  1. Auth0 Access Token: The issue with the missing audience and empty payload in the access token seems to be due to the way Auth0 generates tokens. When the audience is not specified, Auth0 generates an opaque token instead of a JWT. This opaque token is not intended to be decoded and used by clients. It's only useful for the /userinfo endpoint. If you want a JWT from Auth0, you need to specify the audience parameter during the authorization request. However, as you mentioned, this isn't directly possible with Amazon Cognito. One potential workaround could be to use Auth0 as the primary identity provider and then use AWS's Assume Role with Web Identity to authenticate with AWS services. This way, you can get a JWT from Auth0 with the correct audience and payload, and then exchange this token for temporary AWS credentials.

  2. Pre-Token Generation Lambda: You could potentially use a pre-token generation Lambda trigger to modify the tokens issued by Cognito. However, this won't solve the issue of the missing audience in the Auth0 token. This Lambda trigger is used to modify the Cognito tokens, not the Auth0 tokens. As mentioned above, you might need to use Auth0 as the primary identity provider to get the correct Auth0 token.

  3. Client-Side Token Generation: The nextjs-auth0 library provides a getTokenSilently function that can be used to get or refresh the Auth0 tokens. This function can be used to get a new Auth0 token with the correct audience and payload. However, this would require a separate login process for Auth0, which might not be ideal. Another option could be to use the Auth0 Management API to get or refresh the tokens, but this would require storing and managing the client credentials securely.

In summary, it seems like the main issue is the inability to specify the audience during the authorization request with Cognito. One potential solution could be to use Auth0 as the primary identity provider and then use AWS's Assume Role with Web Identity to authenticate with AWS services. This would allow you to get a JWT from Auth0 with the correct audience and payload, and then exchange this token for temporary AWS credentials. However, this might require significant changes to your current authentication flow.

profile picture
answered 10 months ago
  • This is was an extremely helpful and detailed answer, thanks so much @YusufVendii! Ended up going with a strictly Auth0 auth approach given Auth0 has the audience parameter that is required to make authenticated tokenized requests. It works great, and really appreciate all of the different angles you shared that we could go down.

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions