Organisation Member Invitation flow results in state mismatch

Please include the following information in your post:

SDK: nextjs-auth0
SDK Version: 1.5.0
Platform Version: Node v16.2.0

We are attempting to invite users to an organisation and are hitting an issue whereby the callback endpoints (within the default nextjs-auth0 /api/auth/callback endpoint is failing due to a state mismatch error).

Here are the steps taken:

  1. Create Organisation using Management API (Create Organizations)

  2. Enable username/password connection for that Organisation using management API (Enable Organization Connections)

  3. Inviting a list of users to the newly created organisation using the Send Membership Invitations API (Send Organization Membership Invitations)

  4. Invitee receives the invitation email with a login link (defined in tenant settings) which includes the invitation and organization parameters. Example URL https://{host}/api/auth/login?invitation=xgHtmW8bgR0MdvMM3hM9yCPdKE6ufG9Y&organization=org_ssaeGaKNJBfrfsQ&organization_name=test

  5. Invitee receives the invitation email with a login link (defined in tenant settings) which includes the invitation and organization parameters. Example URL https://{host}/api/auth/login?invitation=xgHtmW8bgR0MdvMM3hM9yCPdKE6ufG9Y&organization=org_ssaeGaKNJBfrfsQ&organization_name=test

  6. Modified the default login handler that nextjs-auth0 provides in order to forward the incoming organization and invitation params and set them as custom authorization params.

export default async function loginHandler(req: NextApiRequest, res: NextApiResponse) {
    return await handleLogin(req, res, {
        authorizationParams: {
            organization: req.query.organization as string,
            invitation: req.query.invitation as string,
        },
    });
}
  1. The library redirects the user to the /authorize endpoint, forwarding the organization and invitation values and the user is presented with the custom organisation-branded invitation acceptance screen.

  2. The user enters a password, and clicks continue. They are presented with a consent page where they authorize the app.

  3. When accepted, auth0 redirects back to the callback handler in nextjs-auth0 with code and state parameters. http://{host}/api/auth/callback?code=QgwBGJrS5suZZMBe&state=eyJyZXR1cm5UbyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMS8ifQ

This is where the callback handler in the SDK fails with an Error stating that there’s a state mismatch:

state mismatch, expected eyJyZXR1cm5UbyI6Ii8ifQ, got: eyJyZXR1cm5UbyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMS8ifQ

When decoding these state JWTs it’s because the returnTo values are different.
SDK expects:

{
  "returnTo": "/"
}

Auth0 is sending:

{
  "returnTo": "http://localhost:3001/"
}

Question is why is Auth0 sending this value and why are these values different during the invitation process?

To attempt to fix this issue, I have added an implementation for getLoginState option in the handleLogin function, in order to send a fixed returnTo value of ‘http://localhost:3001/’.

    return await handleLogin(req, res, {
        getLoginState: () => {
            return {
                redirectTo: 'http://localhost:3001/',
            };
        },
        authorizationParams: {
            organization: req.query.organization as string,
            invitation: req.query.invitation as string,
        },

But this results in the following error:

Error [BadRequestError]: checks.state argument is missing

This means the user hits an “Internal Server Error” page. The interesting this is that the whole invitation process seems to have work, and the invitee does have an active session. But the callback failing prevents the end-to-end flow from working seamlessly.

Any help would be greatly apprechiated.