Account link extension fails with Bad Request error

I have two tenants A and B. In both tenants I have installed the Auth0 Account Link Extension.

My scenario is:

  1. Sign user to my app using a Database Connection with an email address/password.
  2. Logout.
  3. Sign up/login to my app in with a social login provider (in this case Google) with the same email address as in (1)
  4. The Account Linking extension detects that I’ve previously signed up with the email address and asks if I want to link them.
  5. I click “Continue”.
  6. On one tenant it succeeds, on another it errors out.

I’ve checked that in both tenants

  • The version of the Account Link Extension is the same at version 2.6
  • The extension Rule code is the same, and both tenants only have 1 Rule currently, being from the Account Link extension.
  • The client/application created by the extension installation has the same configuration, especially scopes.
  • The properties of the extension are the same (title, logo, etc)

However in tenant A using the extension works, but in tenant B it fails.

Looking at the WebTask logs I saw for tenant B

10:05:37 AM:
 [ACCOUNT_LINK]:  Entered Account Link Rule
10:05:37 AM:
 [ACCOUNT_LINK]:  API call failed:  {
  statusCode: 400,
  error: 'Bad Request',
  message: 'Main identity and the new one are the same.',
  errorCode: 'operation_not_supported'
}
10:05:37 AM:
 [ACCOUNT_LINK]:  [object Object] Error: [object Object]
    at Request.handleResponse [as _callback] (/data/io/node12/13070d62-c31b-432b-9507-9bdb3326f76e/webtask.js:276:18)
  1. This [object Object] is really not helpful at understanding the error :laughing:. Searching the forums I’ve seen other devs who are using social login/account linking getting this. When the user is redirected to my application, I don’t get get much in the logs ?error=access_denied&error_description=[object Object]&state=abc123. So I think there’s a bug here that could be fixed to aid in error reporting

  2. I have no idea why it is working in one tenant but not the other. I’m using the a0deploy tool to keep my tenants in sync and diffing my codebase I can’t see something obvious that I’ve stuffed up.

The error message indicates that the users are already linked. You can check this by looking at the raw JSON for the user and seeing if both are in the identities array.

John

1 Like

Thanks @john.gateley.

I’ve updated the original post with an outline of the scenario I’m testing. I’ve retested it in the failing tenant and I can see that.

  1. When I sign the user up for the first time, the JSON for that user only has one entry in the identities array for the Database connection.
  2. When the user logins with Google, a second user is created with only one entry in the identities array for the google-oauth2 connection.
  3. The linking fails with the error.

I’m starting to wonder if it’s a bug with the code in the extension rule in the way the identities are being merged.

Can you post the following (redacted as needed):
The raw JSON for the two users you are trying to merge.
The API call for the link? (You can put a console.log in the linking rule and use the realtime webtask logs extension to see the output)

Thanks

John

In the rule code at line 127 before the API call, I added

console.log("Link URI: " + linkUri);
console.log("Decoded token: " + JSON.stringify(decodedToken));
console.log("secondary user_id: " + decodedToken.sub, " provider: " + provider);

// existing code at line 127
return apiCall({
  method: 'POST',
  url: linkUri,
  headers,
  json: { user_id: decodedToken.sub, provider: provider }
});

In my app I have two users (I’ve taken two real users and aliased them).

  1. Bruce Wayne - This user is able to create an account in the auth0 users DB, then sign up again with his Google ID and have the Auth0 Linking Extension succeed.
  2. Clark Kent - This user is able to create an account in the auth0 users DB, but when he signs up again with his Google ID and tries to link his accounts it fails with the aforementioned error.

Attached is the

  1. Raw JSON for both users for both connections
  2. The rule weblogs

bruce-combined.json.txt (1.2 KB)
bruce-google-oauth2.json.txt (752 Bytes)
bruce-rule-logs.txt (493 Bytes)
bruce-users-db.json.txt (662 Bytes)
clarke-google-oauth2.json.txt (748 Bytes)
clarke-rule-weblogs.txt (653 Bytes)
clarke-users-db.json.txt (658 Bytes)

I also have kept HAR archives of the signup interactions.

I hope that helps @john.gateley

Hi @kierans777

From your clarke-rule-weblogs.txt file:

Link URI: https://myapp.au.auth0.com/api/v2/users/google-oauth2|987654321/identities
Decoded token: {“sub”:“google-oauth2|987654321”,“email”:"clarke@dailyplanent.com",“base”:“https://myapp.au.auth0.com/api/v2",“iat”:1606643784,“exp”:1606644084,“aud”:“someAudienceId”,“iss”:"https://myapp.au.auth0.com/”}
secondary user_id: google-oauth2|987654321 provider: google-oauth2

[ACCOUNT_LINK]: API call failed: {
statusCode: 400,
error: ‘Bad Request’,
message: ‘Main identity and the new one are the same.’,
errorCode: ‘operation_not_supported’
}

[ACCOUNT_LINK]: [object Object] Error: [object Object]

Note that the user ID in the URL is the google social identity AND THAT SAME USER ID is the java payload of the request. You are indeed trying to link the user to itself.

You need this user ID in the URL (or the payload): “user_id”: “auth0|def456”,

John

After the HARs was examined, it’s been found that for the “clarke” account the extension requests an authentication from Auth0 but the connection parameter is missing, so the user does not have the opportunity to log in with the email/password credentials. This, in turn, causes Auth0 to immediately continue the flow with the Google identity, and then the rule tries to link those two (same) identities. This of course is the conclusion you came to @john.gateley.

The now question is why is the rule code dropping the connection parameter?

The rule hard codes the tenant information

var config = {
  endpoints: {
    linking: 'https://tenant-A.au12.webtask.io/abc123',
    userApi: auth0.baseUrl + '/users',
    usersByEmailApi: auth0.baseUrl + '/users-by-email'
  },
  token: {
    clientId: 'fkjafadksfakfakdfkald',
    clientSecret: '********',
    issuer: auth0.domain
  }
};

And this was the root cause. When the rule was deployed into tenant B, the rule code from the extension was overwritten by code from tenant A, so the rule was using the extension host in tenant A.

This goes against Auth0 best practise as the code should be tenant agnostic with the tenant information being injected via configuration. I’ve since updated the code to have keyword placeholders. I’ve also updated my build pipeline to check for hardcoded config values and fail if any are found.

1 Like

@kierans777

Excellent! I am glad you found it.

John

3 Likes