Rule: Link accounts -> Missing authentication

I’ve added this new Rule that shall ‘link-accounts-with-same-ssn(it’s based upon Link-Users-With-Same-Email). The problem is that I’m getting:
statusCode: 401,
error: ‘Unauthorized’,
message: ‘Missing authentication’

The first request is working fine with the same bearer. What could I’ve missed? :pensive:

The Rule:

function (user, context, callback) {
  const request = require('request');
  const swedishBankIdAnotherDevice_connectionId = 'con_myswedishbankid_connectionid';
  const isSwedishBankIdConnection = context.connectionID === swedishBankIdAnotherDevice_connectionId;

  // Check if connection is SwedishBankId,
  // we shouldn't automatically merge accounts if this is not the case.
  if (!isSwedishBankIdConnection) {
    return callback(null, user, context);
  }

  if (!user.app_metadata || !user.app_metadata.userSocialSecurityNumber || user.app_metadata.userSocialSecurityNumber.length !== 12) {
    return callback(new Error('[!] Rule: BankIdUser is missing the required property app_metadata.userSocialSecurityNumber'));
  }

  const userApiUrl = auth0.baseUrl + '/users';
  const userSearchQueryUrl = userApiUrl + '?q=app_metadata.userSocialSecurityNumber%3A%22' + user.app_metadata.userSocialSecurityNumber + '%22&search_engine=v3';
  request({ **// <<< works fine**
    url: userSearchQueryUrl,
    headers: {
      Authorization: 'Bearer ' + auth0.accessToken
    }
  },
  function(err, response, body) {
    if (err) return callback(err);
    if (response.statusCode !== 200) return callback(new Error(body));

    var data = JSON.parse(body);
    data = data.filter(function(u) {
      return u.user_id !== user.user_id;
    });
    if (data.length > 1) {
      return callback(new Error('[!] Rule: Multiple user profiles already exist - cannot select base profile to link with'));
    }
    if (data.length === 0) {
      console.log('[-] Skipping link rule');
      return callback(null, user, context);
    }

    const originalUser = data[0];
    const provider = user.identities[0].provider;
    const providerUserId = user.identities[0].user_id;
    request.post({
      url: userApiUrl + '/' + originalUser.user_id + '/identities',
      headers: {
        Authorization: 'Bearer ' + auth0.accessToken
      },
      json: {
        provider: provider,
        user_id: String(providerUserId)
      }
    }, function(err, response, body) {
      if (response.statusCode >= 400) {
        **return callback(new Error('Error linking account: ' + response.statusMessage));** **// <<<< this is where I'm getting statusCode: 401, error: 'Unauthorized', message: 'Missing authentication'**
      }

      context.primaryUser = originalUser.user_id;
      callback(null, user, context);
    });
  });
}

@joakim.neatsoft,

Take a look at your access token and see what scopes you are granted see if you have the appropriate ones.

Also, check your auth0 logs and see if there is a more detailed message.

Everything looks okay with the rule at first glance.

Let me know.

Thanks,
Dan

I’ve the following scopes in the token:

"scopes": {
    "users": {
      "actions": [
        "read",
        "update"
      ]
    }
}

But it also says “Invalid Signature” when I’m using jwt.io to decode it, not sure what thats about.

I also have this from Auth0-logs:

image

{
      "date": "2019-12-04T06:25:19.399Z",
      "type": "f",
      "description": "Error linking account: Unauthorized",
      "connection": "criipto-verify-SE-BankID-Another-De",
      "connection_id": "con_<my connection>",
      "client_id": "ePbm……….u8DPaJ",
      "client_name": "Frontend test",
      "ip": "<my ip>",
      "user_agent": "Chrome 78.0.3904 / Windows 10.0.0",
      "details": {
        "body": {
          "wa": "wsignin1.0",
          "wresult": "<trust:RequestSecurityTokenResponseCollection xmlns:trust=…… <alot of stuff here>…….</trust:RequestSecurityTokenResponseCollection>",
          "wctx": "xeGcDj-5p……….TIIwweOBLo"
        },
        "qs": {},
        "connection": "criipto-verify-SE-BankID-Another-De",
        "error": {
          "message": "Error linking account: Unauthorized",
          "oauthError": "access_denied",
          "type": "oauth-authorization"
        },
        "session_id": "1yz_Egg0………yLgSw4vtL"
      },
      "hostname": "<mydomain>.eu.auth0.com",
      "user_id": "adfs|criipto-verify-SE-BankID-Another-De|41a55………b3368e2",
      "user_name": "JoakimBTest BTest",
      "strategy": "adfs",
      "strategy_type": "enterprise",
      "audience": "https://<tenant>.eu.auth0.com/userinfo",
      "scope": [
        "openid",
        "profile",
        "email"
      ],
      "log_id": "900201912040……….360811622418",
      "_id": "900201912040…….11622418",
      "isMobile": false
    }

It could be worth mentioning that when I loggin the application starts looping the login with the message from the Rule above (this might be standard behavior when the rule fails in this way?). It generates this:

The scenario for my application is this:
We’ve added Criiptos solution to Auth0 to have some users be able to login with Swedish BankId.

  • Create user Username/Password (add social security number as metadata, will be used to link accounts)
  • User signs in with BankId, the user gets created in Auth0. The rule described above kicks in and link the new BankId-user with the manually created user (username/password)

Application structure:

  • Client (React using @auth0/auth0-spa-js)
  • API (.Net Core)

@joakim.neatsoft,

Can you try requesting a token for the management api with the update:current_user_identities scope and see if you still get the error?

Here is the relevant node library:

Ok I did try to run it directly in the rule with no success “ManagementClient is not a constructor”.
After that I ran it from my machine using Node with success:

EDIT:
I can’t find the scope “update:current_user_identities” under my “Auth0 Management API \ Permission-tab”.

Ok so I’ve a working solution now. I just added this code after const providerUserId = user.identities[0].user_id

// Start linking accounts
      var ManagementClient = require('auth0@2.9.1').ManagementClient;
      var management = new ManagementClient({
        token: auth0.accessToken,
        domain: auth0.domain
      });
      var params = {
        provider: provider,
        user_id: providerUserId,
        connection_id: context.connectionID
      };

      management.linkUsers(originalUser.user_id, params, function (err, user) {
        if (err) {
          return callback(new Error('Error linking account: ' + err));
        }
        console.log('PrimaryUser: ' + originalUser.user_id + ' got linked with user: ' + providerUserId);
      });

thank you for all the help!

Glad you got it working!

You may want to update to the current auth0 package version available in rules, 2.19.0.

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