Unable to redirect to site after linking account

Hi,
I’m linking two accounts using the identities endpoint as follows. Post linking, I want to redirect to my site as the primary user. However, after the following call, I end up with a 500 error (Oops!, something went wrong server_error: Internal error). Is anyone able to help me understand what might be wrong?

In the following, the ${fullTargetId} is the existingIdentity.provider+“|”+existingIdentity.user_id
and the ${newToken} is the token for the Auth0 Management API.

The call below does link the new account into the existing one with the expected Raw JSON.

 
   const url = `https://${event.secrets.domain}/api/v2/users/${fullTargetId}/identities`;
    var options = {
    method: 'POST',
    url: url,
    headers: {
      'Content-Type': 'application/json', 
      'Accept': 'application/json',
      'Authorization': `Bearer ${newToken}`
    },
    data: {
      "provider": event.connection.strategy,
      "connection_id": event.connection.id,
      "user_id": event.user.user_id
    }
  };

  await axios.request(options).then(function (response) {
    console.log(response.data);
    api.redirect.sendUserTo("http://localhost:3000");
  }).catch(function (error) {
    console.error(error);
  });

Hi @stephen.graham,

Welcome to the Auth0 Community!

If the two accounts are being linked correctly without issues, you could consider allowing the authentication flow to continue without a redirect to http://localhost:3000 in your Action script.

Instead, you can redirect your users to your preferred URL by specifying it in your application’s Allowed Callback URLs and including it in the redirect_uri query parameter in your login request.

I would also mention that you can change the primary user of the authentication flow in the Action script by calling api.authentication.setPrimaryUser(primary_user_id).

Finally, it might be worth reviewing our account linking with Actions example as a reference.

Thanks,
Rueben

Hi,
Thanks Rueben, but I’m still having trouble with this. I’ve removed the api.redirect.sendUserTo() and so the linking is the end of the flow, but I’m still getting the same “Oops! something went wrong” 500 server_error: internal error.

I am using the unmodified JS Sample"My App" as a SPA; I’ve got the http://localhost:3000 in the Allowed Callback URLs, Allowed Logout URLs and Allowed Web Origins. Apart from “My App”, I have the “API Explorer Application” as a M2M with access & all permissions to the “Auth0 Management API”.

The first user (using Google Mail) logs in fine. The second user (using email/password with the same email as the Google Mail) signs in okay; the account links correctly; the User Management->Users->->Raw JSON looks good; the Webtasks looks correct; and the user is presented with the dialog to “Authorize App with Accept/Decline buttons”. However, once I press “Accept”, I get the “Oops! something went wrong” with a 500 internal server error.

The code is below.

var axios = require("axios").default;

exports.onExecutePostLogin = async (event, api) => {
  console.log("auto-account-link: onExecutePostLogin: Started");

  console.log("getting Session Token");
  var options = {
    method: 'POST',
    url: `https://${event.secrets.domain}/oauth/token`,
    headers: {'content-type': 'application/x-www-form-urlencoded'},
    data: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: event.secrets.m2mClientId, // The clientId for the API Explorer Application
      client_secret: event.secrets.m2mClientSecret, // For the API Explorer Application
      audience: `https://${event.secrets.domain}/api/v2/`
    }) 
  };

  axios.request(options).then(function (response) {
    const sessionToken = response.data['access_token'];
    console.log("About to search for candidateUsers with email="+event.user.email+" sessionToken "+sessionToken); 
    var options = {
      method: 'GET',
      url: `https://${event.secrets.domain}/api/v2/users-by-email`, 
      params: {email: event.user.email},
      headers: {authorization: `Bearer ${sessionToken}`}
    };
    axios.request(options).then(function (response) {
      processCandidates(event,sessionToken,response.data);
    }).catch((error) => {
      console.error(error);
    });
  }).catch(function (error) {
    console.error(error);
  });
}
async function processCandidates(event,sessionToken,candidateUsers) {
    console.log("Found candidateUsers ..."); console.dir(candidateUsers);
    // Only one user is returned then no linking necessary
    if (!Array.isArray(candidateUsers)) {
      console.log("Only 1 candidateUser found => no linking necessary");
      return;
    }
    // Get the identities of the user
    const candidateIdentities = candidateUsers.flatMap((user) => user.identities);
    if(candidateIdentities.length <= 1) {
      console.log("only 1 candidateIndentites found - nothing to do ...");
      console.dir(candidateIdentities);
      return;
    }
    // Returns the candidate that already exists 
    const oldExistingIdentity = candidateIdentities.find(
      (identity) => identity.provider !== event.connection.strategy
    );
    await linkUserAccounts(event, sessionToken, oldExistingIdentity.provider + "|" + oldExistingIdentity.user_id);
    console.log(`linked.`);
}

/**
 * Calls the management api and links the old existing user into the new current user.
 */
async function linkUserAccounts(event, sessionToken, fullTargetId) {
    const url = `https://${event.secrets.domain}/api/v2/users/${fullTargetId}/identities`;
    var options = {
    method: 'POST',
    url: url,
    headers: {
      'Content-Type': 'application/json', 
      'Accept': 'application/json',
      'Authorization': `Bearer ${sessionToken}`
    },
    data: {
      "provider": event.connection.strategy,
      "connection_id": event.connection.id,
      "user_id": event.user.user_id
    }
  };

  await axios.request(options).then(function (response) {
    return;
  }).catch(function (error) {
    console.log("error...");
    console.error(error);
  });
}

The raw JSON is (using xxxxxxxxxxx to blank things)

{
    "created_at": "2025-03-13T01:14:37.321Z",
    "email": "xxxxxxxxxxx@gmail.com",
    "email_verified": true,
    "family_name": "xxxxxxxxxxx",
    "given_name": "xxxxxxxxxxx",
    "identities": [
        {
            "provider": "google-oauth2",
            "user_id": "109774375892536849889",
            "connection": "google-oauth2",
            "isSocial": true
        },
        {
            "profileData": {
                "email": "xxxxxxxxxxx@gmail.com",
                "email_verified": false
            },
            "connection": "Username-Password-Authentication",
            "provider": "auth0",
            "user_id": "67d23215684e8a99a822b064",
            "isSocial": false
        }
    ],
    "name": "xxxxxxxxxxx xxxxxxxxxxx",
    "nickname": "xxxxxxxxxxx",
    "picture": "https://lh3.googleusercontent.com/a/ACg8xxxxxxxxxxxs96-c",
    "updated_at": "2025-03-13T01:17:10.844Z",
    "user_id": "google-oauth2|109774375892536849889",
    "last_ip": "14.200.69.118",
    "last_login": "2025-03-13T01:14:37.317Z",
    "logins_count": 1,
    "blocked_for": [],
    "guardian_authenticators": [],
    "passkeys": []
}

The Webtasks logfile is below with xxxxxxxxxxx blanking things …

12:14:38 PM:
 getting Session Token
12:14:38 PM:
 About to search for candidateUsers with email=xxxxxxxxxxx@gmail.com sessionToken eyJhxxxxxxxxxxxDEzSsQ
12:14:38 PM:
 Found candidateUsers ...
12:14:38 PM:
 [
  {
    created_at: '2025-03-13T01:14:37.321Z',
    email: 'xxxxxxxxxxx@gmail.com',
    email_verified: true,
    family_name: 'xxxxxxxxxxx',
    given_name: 'xxxxxxxxxxx',
    identities: [ [Object] ],
    name: 'xxxxxxxxxxx xxxxxxxxxxx',
    nickname: 'xxxxxxxxxxx',
    picture: 'https://lh3.googleusercontent.com/a/ACgxxxxxxxxxxx6-c',
    updated_at: '2025-03-13T01:14:37.321Z',
    user_id: 'google-oauth2|109774375892536849889',
    last_ip: '14.200.69.118',
    last_login: '2025-03-13T01:14:37.317Z',
    logins_count: 1
  }
]
12:14:38 PM:
 only 1 candidateIndentites found - nothing to do ...
12:14:38 PM:
 [
  {
    provider: 'google-oauth2',
    access_token: 'yaxxxxxxxxxxx0177',
    expires_in: 3598,
    user_id: '109774375892536849889',
    connection: 'google-oauth2',
    isSocial: true
  }
]

second login attempt using email/password with same email as above


12:17:10 PM:
 getting Session Token
12:17:10 PM:
 About to search for candidateUsers with email=xxxxxxxxxxx@gmail.com sessionToken eyJhbxxxxxxxxxxx0omFVg8g
12:17:10 PM:
 Found candidateUsers ...
12:17:10 PM:
 [
  {
    created_at: '2025-03-13T01:17:09.998Z',
    email: 'xxxxxxxxxxx@gmail.com',
    email_verified: false,
    identities: [ [Object] ],
    name: 'xxxxxxxxxxx@gmail.com',
    nickname: 'xxxxxxxxxxx',
    picture: 'https://s.gravatar.com/avatar/bfecxxxxxxxxxxx%2Fpo.png',
    updated_at: '2025-03-13T01:17:09.998Z',
    user_id: 'auth0|67d23215684e8a99a822b064',
    last_ip: '14.200.69.118',
    last_login: '2025-03-13T01:17:09.995Z',
    logins_count: 1
  },
  {
    created_at: '2025-03-13T01:14:37.321Z',
    email: 'xxxxxxxxxxx@gmail.com',
    email_verified: true,
    family_name: 'xxxxxxxxxxx',
    given_name: 'xxxxxxxxxxx',
    identities: [ [Object] ],
    name: 'xxxxxxxxxxx xxxxxxxxxxx',
    nickname: 'xxxxxxxxxxx',
    picture: 'https://lh3.googleusercontent.com/a/ACg8xxxxxxxxxxx96-c',
    updated_at: '2025-03-13T01:14:37.321Z',
    user_id: 'google-oauth2|109774375892536849889',
    last_ip: '14.200.69.118',
    last_login: '2025-03-13T01:14:37.317Z',
    logins_count: 1
  }
]
12:17:10 PM:
 linked.

Okay, got it thanks.

  1. Mixing async with then mistakes
  2. Not setting Primary User

No further help required, thanks!

1 Like

Hi @stephen.graham,

I’m glad you were able to resolve the issue!

Feel free to reach out again if you have any other issues.

Cheers,
Rueben

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.