AzureAD / microsoft-authentication-library-for-dotnet

Microsoft Authentication Library (MSAL) for .NET
https://aka.ms/msal-net
MIT License
1.39k stars 341 forks source link

Token cache key for Azure AD B2C users #4057

Closed WenningQiu closed 1 year ago

WenningQiu commented 1 year ago

I have noticed that the token cache key for Azure AD B2C users is a combination of the policy id and the tenant id, e.g. "-b2c_1a_signin_xxxxxdev.2d3c6047-afa5-441b-8282-314f6dfe18d4". I am afraid that the access token for different users will get mixed up in the token cache.

I have a few questions:

  1. I suspect that Microsoft.Identity.Web might just pull the token cache key from the access token, as the "home_account_id" field contains the same value (see the screenshot below), but I need folks to confirm that.
  2. If that's the case, is there a way to configure Azure B2C use use a better key/id?
  3. Can Microsoft.Identity.Web be enhanced to compose cache keys that are unique for different B2C users?

image

jmprieur commented 1 year ago

Which flow is it, @WenningQiu ? cc: @bgavrilMS @pmaytak

WenningQiu commented 1 year ago

Auth code.

bgavrilMS commented 1 year ago

@WenningQiu - can you think of a scenario that would be broken?

TLDR; the home_account_id is made of the policy and the oid. The oid is "Object ID", uniquely identifies the user.

Both Access Tokens and Refresh Tokens are internally stored by:

(the last 2 are not used for refresh tokens).

WenningQiu commented 1 year ago

@bgavrilMS oid is set to a unique user identifier in the policy and there is an objectidentifier claim which has that unique identifier value. However oid claim is only set by the RelyingParty, not sure if B2C requires it to exist at earlier stages in the pipeline?

    <TechnicalProfile Id="PolicyProfile">
      <DisplayName>PolicyProfile</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="displayName" />
        <OutputClaim ClaimTypeReferenceId="givenName" />
        <OutputClaim ClaimTypeReferenceId="surname" />
        <OutputClaim ClaimTypeReferenceId="email" />
        <OutputClaim ClaimTypeReferenceId="samAccountName" PartnerClaimType="sub" />
        <OutputClaim ClaimTypeReferenceId="samAccountName" PartnerClaimType="oid" />
        <OutputClaim ClaimTypeReferenceId="identityProvider" />
        <OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />
        <OutputClaim ClaimTypeReferenceId="samAccountName" PartnerClaimType="employeeId" />
      </OutputClaims>
      <SubjectNamingInfo ClaimType="sub" />
    </TechnicalProfile>

image

bgavrilMS commented 1 year ago

Not sure I understand what you mean by oid is set by the RP. oid is known by the token issuer (B2C).

Note that MSAL's force the token issuer to add the oid in the token response. We do not rely on it being present in the IdToken.

image

See the client_info in the picture above. This will have the oid. It's a simple base64 encoded json with oid and policy. Apps using MSAL do not have the option of not requesting "client info", because MSAL uses the data for token caching.

WenningQiu commented 1 year ago

@bgavrilMS My RP sets oid in the red box below. Will that mess up home_account_id? image

bgavrilMS commented 1 year ago

No, home_account_id is entirely driven by the token issuer (B2C) and was specially designed to help MSALs with token caching.

WenningQiu commented 1 year ago

I tried a user flow and saw unique home_account_id being created:

"home_account_id": "f9a382ee-3b9b-4dd0-ae33-2eb1eeae0383-b2c_1_netiqsignupsignin.2d3c6047-afa5-441b-8282-314f6dfe18d4"

So it appears that the problematic home_accunt_id has the initial guid (oid, I suppose) missing. I think I need to adjust my policy to make oid available to earlier stages of the pipeline.

WenningQiu commented 1 year ago

"objectId" claim is part of the generated "home_account_id".

Once I make sure "objectId" claim has a unique value, the token cache key is unique for the user.