When using Azure AD as an Identity Provider in Azure AD B2C, idp_access_token returned after signin causes error when passed to acquireTokenOnBehalfOf

114 views Asked by At

Environment:

  • Node.js
  • "@azure/msal-node": "^2.6.0"

Short Version:

When calling this:

const response = await confidential_client_application.acquireTokenOnBehalfOf(on_behalf_of_request);

I am getting this error:

Error obtaining token on behalf of user:

ServerError: invalid_grant: 50013 - [2023-12-28 01:15:26Z]:

AADSTS50013: Assertion failed signature validation.

[Reason - Key was found, but use of the key to verify the signature failed.,

Thumbprint of key used by client: 'E41DE************ED91', Found key 'Start=12/05/2023 17:16:57, End=12/05/2028 17:16:57',

Please visit the Azure Portal, Graph Explorer or directly use MS Graph to see configured keys for app Id '00000000-0000-0000-0000-000000000000'.

Review the documentation at https://docs.microsoft.com/en-us/graph/deployments to determine the corresponding service endpoint and https://docs.microsoft.com/en-us/graph/api/application-get?view=graph-rest-1.0&tabs=http to build a query request URL, such as 'https://graph.microsoft.com/beta/applications/00000000-0000-0000-0000-000000000000'].

The token I am passing through to acquireTokenOnBehalfOf is the idp_access_token returned after an Azure AD user signs in via Azure AD B2C.

Long Version:

I have two tenants:

01) Azure AD Home Tenant (a 'Developer Program' tenant)

02) Azure AD B2C Tenant (in a different tenant)

I have four app registrations:

In B2C Tenant:

01) B2C_SignIn_App_Registration

In Azure AD Home Tenant:

02) InternalUser_M365_Access_App_Registration (has Delegated permissions on Graph API)

03) ExternalUser_M365_Access_App_Registration (has Application permissions on Graph API)

04) Admin_M365_Access_App_Registration (has Application permissions on Graph API)

Identity Provider:

The 'home' Azure AD tenant is set up as an Identity Provider in the B2C tenant, which allows home tenant Azure AD users to login ('internal users'), as well as users created directly in Azure AD B2C ('external users').

Home Tenant M365 Access Control:

To control access to M365 resources in the home tenant:

  • Internal users will be given a token from InternalUser_M365_Access_App_Registration
  • External users will be given a token from ExternalUser_M365_Access_App_Registration
  • The application itself will be given a token from Admin_M365_Access_App_Registration

Internal users access will therefore be limited by:

  • The relevant app registration permissions
  • Their own account permissions
  • Application roles assigned to them from InternalUser_M365_Access_App_Registration and present in their token claims which can be used as control conditions in the app's code

External users access will therefore be limited by:

  • The relevant app registration permissions
  • Custom attributes in their user profiles that are present in their token claims which can be used as control conditions in the app's code

Sign In Process:

01) Internal and External Users signin via B2C_SignIn_App_Registration

02) After sign in, application code checks for the presence of the idp_access_token in the response.

03) If that idp_access_token property is present, it indicates they are an INTERNAL user, otherwise they are an EXTERNAL user

04) If they are an INTERNAL user, I am passing the idp_access_token through to an 'on-behalf-of' token request, eg:

// these are the settings related to the app registration named `InternalUser_M365_Access_App_Registration`
msal_config = {
    auth: {
        clientId: process.env.APP_CLIENT_ID_InternalUser_M365_Access,
        clientSecret: process.env.APP_CLIENT_SECRET_InternalUser_M365_Access,
        authority: `https://login.microsoftonline.com/${process.env.TENANT_ID_HOME_TENANT}`
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: msal.LogLevel.Verbose,
        }
    }
};

on_behalf_of_request = {
    oboAssertion: idp_access_token,
    scopes: ["https://graph.microsoft.com/.default"]   
};


// create msal instance
const confidential_client_application = new msal.ConfidentialClientApplication(msal_config);

// acquire token
const response = await confidential_client_application.acquireTokenOnBehalfOf(on_behalf_of_request);

The reason I am passing through the idp_access_token as the oboAssertion value, instead of the accessToken value, is because the response returned from the initial sign in has empty string values for accessToken and tenantId and an empty array for scopes. However, it does have a value for idp_access_token.

05) The acquireTokenOnBehalfOf request is returning the error message specified at the start of this post.

06) The desired behaviour is that the error does not occur and that a token is returned to the internal user from the app registration named InternalUser_M365_Access_App_Registration.

0

There are 0 answers