Decode session token in continue action

Hello auth0, I’m working on the account linking logic and when linking is done using my own linking service I want to redirect the user back to the onContinuePostLogin action together with session_token, however, session_token I send is considered as invalid one for some reason…

Here is my continue state sent from the auth0 action to the linking service:

hKFo2SBaWnhWQnhWVm5faHAwNEh5dnBVdjkyRFFfNWc3a3Q5daFuqHJlZGlyZWN0o3RpZNkgenZRX1lJMVozNjFHa0R5UjMtQjhvMmJZYXVlWlVjTEKjY2lk2SA3eTZ5Q2h2dmFMV0NkNGZqQzZhdFhVZ2x0R0JQajA4Rw

Here is my session_token sent to my linking service:

eyJhbGciOiJIUzI1NiIsInR...[OBFUSCATED]

So the action context as you can see is:
"iat": 1714979365, "iss": "[MYTENANT].eu.auth0.com", "sub": "google-oauth2|100824245565501739142",

now, after account linking I want to send data back to auth0, so I create a session token myself and sign it with the same secret with HS256 alg.

so here is URL that I send user to https://[MYTENANT].eu.auth0.com/continue?state=hKFo2SBaWnhWQnhWVm5faHAwNEh5dnBVdjkyRFFfNWc3a3Q5daFuqHJlZGlyZWN0o3RpZNkgenZRX1lJMVozNjFHa0R5UjMtQjhvMmJZYXVlWlVjTEKjY2lk2SA3eTZ5Q2h2dmFMV0NkNGZqQzZhdFhVZ2x0R0JQajA4Rw&session_token=eyJhbGciOiJIUzI1NiIsInR5c..[OBFUSCATED]

where as you can see state is:
KFo2SBaWnhWQnhWVm5faHAwNEh5dnBVdjkyRFFfNWc3a3Q5daFuqHJlZGlyZWN0o3RpZNkgenZRX1lJMVozNjFHa0R5UjMtQjhvMmJZYXVlWlVjTEKjY2lk2SA3eTZ5Q2h2dmFMV0NkNGZqQzZhdFhVZ2x0R0JQajA4Rw (same as above one)

and session token is:
eyJhbGciOiJIUzI1NiIsInR5c..[OBFUSCATED]

or with decoded claims:
{ "iss": "[MYTENANT].eu.auth0.com", "sub": "google-oauth2|100824245565501739142", "state": "hKFo2SBaWnhWQnhWVm5faHAwNEh5dnBVdjkyRFFfNWc3a3Q5daFuqHJlZGlyZWN0o3RpZNkgenZRX1lJMVozNjFHa0R5UjMtQjhvMmJZYXVlWlVjTEKjY2lk2SA3eTZ5Q2h2dmFMV0NkNGZqQzZhdFhVZ2x0R0JQajA4Rw", "user_id": "auth0|6638820ef54520ecca12593a", "iat": 1714979386, "exp": 1714979406 }

note that: [MYTENANT] isn’t really sensitive but I replaced it here, it’s still can be found in JWT

as you can see “iss” is here, “sub” is also equal to the sub from onExecutePostLogin action, “state” is also the same and present.

So I’m really confused and can’t figure it out. I also tried to request /continue using POST request as the docs say, but the outcome is the same: “The session token is invalid: State in the token does not match the /continue state.”, but you can clearly see that it does match…

It makes me think that docs are either incorrect or it never worked… Please advice.

Hi @elja1989,

Thanks for reaching out to the Auth0 Community!

Firstly, I must obfuscate all the sensitive information you shared in your initial post. This is for security reasons and to ensure we do not expose sensitive information like your access token.

After checking your first access token, I noticed that the user already has the secondary user linked to their profile, as shown under the identities array:

  "identities": [
    {
      "connection": "Username-Password-Authentication",
      "user_id": "6638820ef54520ecca12593a",
      "provider": "auth0",
      "isSocial": false
    }

This user_id matches the user_id of the secondary user.

So, in this case, you should use the primary account to authenticate, which means you should use the initial access token. You do not need to create a new access token and send it back for consumption. This could be why the token was invalid.

Could you give that a try and let me know how it goes?

Thanks,
Rueben

Thanks for the response. I apologize, but your explanation doesn’t quite make sense to me. Perhaps I wasn’t very clear when describing my case.

Here’s my situation:

  1. The user logs in using Auth0.
  2. Then, a custom action triggers and utilizes the Management API to check if another user with the same email exists in Auth0. If yes, the system redirects to a linking service (my own Next.js app). Before the redirect, the Auth0 action also creates a session token using api.redirect.encodeToken and includes the found identities in the payload.
  3. In the linking service, the session token is validated and decoded. It displays the end-user identities to link with and requests authentication using the chosen identity.
  4. Once the identity ownership is verified (using OIDC implicit flow), the Management API is used to link the user identity who initiated this flow (user from step 1) with the just-verified identity from step 3. Upon completion, it redirects back to the Auth0 action using the /continue URL and provides a NEW session token created by myself and a state received upon redirect from custom auth0 action. The payload of this token is simple; it only includes the payload required by Auth0 to validate it (sub, iss, state), and the new user_id, which is now primary.
  5. In the Auth0 continue action, I validate this token and set the new primary identity for the user.

And so in step 5 token validation never passed… I provided not OBFUSCATED tokens because, clients can see them in query params, and it’s a test tenant, and for your information.

The thing is, the tokens you’re referring to as access tokens are not actually access tokens but custom JWT tokens (session_tokens), created with api.redirect.encodeToken. I’ve already modified my initial implementation to use app_metadata instead of sending another session token back to the continue action. However, during this process, I noticed that if you link the original user to another user during the redirect and before the continue redirect, a state sent to continue action can’t be validated because technically, the user doesn’t exist anymore, and their identities are now part of the other user’s identities and I believe this is the root issue. So, if anyone is building a linking logic for the current user where the current user who initiated the redirect has been merged into another user, it will cause issues validating your state when you redirect back to continue. Therefore, you have to perform linking inside the continue action, or probably link verified identity into an initial user who tried to login and not vise-versa like in my case.