Event.transaction.state not same sent to redirect

I’m trying to pass data back to Auth0 when user redirected to external site. I’m trying to follow this guide Redirect with Actions but it doesn’t work for me, it returns me an error The session token is invalid: State in the token does not match the /continue state.

I found this answer The session token is invalid: State in the token does not match the /continue state where suggestion was put state inside the session JWT, but I don’t know where to get state value inside the onExecutePostLogin function. I tried to use event.transaction.state but it deviates with the state value passed as query parameter. As a result I’m still getting the same error.

Here is my steps.

  1. Click login
  2. Run onExecutePostLogin
  3. Encode token
const sessionToken = api.redirect.encodeToken({
      payload: {},
      secret: event.secrets.SESSION_TOKEN_SECRET,
      expiresInSeconds: 120,
    })
  1. Make redirect
api.redirect.sendUserTo(`${event.secrets.WEB_URL}/auth/linking`, {
      query: {
        session_token: sessionToken,
      },
    })
  1. External site redirects user to <auth0_domain>/continue?session_token=<session_token_generated_in_on_execute_post_login>&state=<state_passed_as_query_parameter_by_send_user_to_function>
  2. Run onContinuePostLogin
  3. Validate token
const payload = api.redirect.validateToken({
    secret: event.secrets.SESSION_TOKEN_SECRET,
    tokenParameterName: 'session_token',
  })

And here I got the error about state mismatch. My question is where to get actual state value in onExecutePostLogin to put it inside the session JWT? Or what another way to pass data safely from onExecutePostLogin to onContinuePostLogin? Thanks!

this is a copy from someone elses issue that wasnt help and im experiencing the same issue. I sent the session token with a property called ‘state’ but the state from event.transaction.state versus what was sent to the external url

/**
* Handler that will be called during the execution of a PostLogin flow.
*
* @param {Event} event - Details about the user and the context in which they are logging in.
* @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
*/
exports.onExecutePostLogin = async (event, api) => {
console.log(event.transaction)

const YOUR_AUTH0_DOMAIN = event.request.hostname;
  console.log("1. POSTLOGIN CALLED");
  const state = event.transaction?.state
  // Craft a signed session token
  const token = api.redirect.encodeToken({
    secret: event.secrets.SESSION_TOKEN_SECRET,
    expiresInSeconds: 360000, 
    payload: {
      state: event.transaction?.state,
      // Custom claims to be added to the token
      email: event.user.email,
      externalUserId: 1234,
      continue_uri: `https://${YOUR_AUTH0_DOMAIN}/continue`,
    },
  });
  console.log("end")

  api.redirect.sendUserTo("http://localhost:4200/consent", {
    query: { session_token: token }
  });
};


/**
* Handler that will be invoked when this action is resuming after an external redirect. If your
* onExecutePostLogin function does not perform a redirect, this function can be safely ignored.
*
* @param {Event} event - Details about the user and the context in which they are logging in.
* @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
*/
exports.onContinuePostLogin = async (event, api) => {
  const payload = api.redirect.validateToken({
    secret: event.secrets.SESSION_TOKEN_SECRET,
    tokenParameterName: 'session_token',
  });
  console.log(event.request.query)
  console.log("success")
};