5

I'm in the process of updating an internal app with OIDC and SCIM with the goal of having sign-on and provisioning driven by Azure AD.

Looking at the Azure docs for OIDC and SCIM, there seems to be a discrepancy around how to uniquely identify users. Coming into this project, I presumed the user's ObjectId would be made readily available.

Using a test enterprise app, and navigating to user attribute mapping for provisioning: The default mappings include userPrincipalName (upn) mapping to userName with the highest matching precedence. And the inability to modify that mapping. Also, mailNickname is mapped to externalId, without any matching precedence, but this could be changed to map objectId to externalId and add matching if desired.

Meanwhile, using another test enterprise app for OIDC, the sub claim is not the user's Object Id. I think I read the sub claim is a unique value for the user and the enterprise app (which means it's no good to anyone). Under Token Configuration, there does not seem to be the option of adding the Object Id as an optional claim at all. There is the option to add the upn as an optional claim, but the description explicitly states not use the value for keying the user.

An identifier for the user that can be used with the username_hint parameter; not a durable identifier for the user and should not be used to key data

This comment makes sense to me. upns can change over time and should not be used to identify users for the same reasons that you shouldn't rely on a user's email not changing.

All that being said; if I want Azure AD to provision users via SCIM and then allow those users to sign in with OIDC, how should I uniquely identify the user record as the service provider?

Matt R. Wilson
  • 7,268
  • 5
  • 32
  • 48

2 Answers2

1

I can't say this is the correct answer, but after all the research I can do I wanted to share the Azure workaround I went with, in hopes that it helps the likes of @TheTrav.

On the OIDC side; include the profile scope to ensure we get back the oid claim. https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens#payload-claims

Then when I'm resolving the claims, if I have an oid claim and the iss claim starts with either "https://login.microsoftonline.com/" or "https://sts.windows.net/", I proceed with the oid claim instead of the sub claim as the identifier for the user.

On the SCIM side: I went down the path I alluded to in the question. Remapping externalId from mailNickname to objectId in the Azure AD app. Then on our side we have a setting that allows us to denote which user attribute to map to the user's login ID for a given SCIM IdP. So for Azure AD cases, instead of using the default userName, we instead map externalId.

In the end, this does mean that we end up using Azure's objectId to ID and log in users. It just takes a few extra hoops.

Matt R. Wilson
  • 7,268
  • 5
  • 32
  • 48
  • In case it helps: for Azure AD (at least), you can also consider/question whether adding a custom claim can help - return the information for you; a bit tricky to understand/set-up first time around, but not too bad once you've got it right. – DennisVM-D2i Jan 07 '23 at 23:49
0

Using the account ID is the standard option when using SCIM, so the oid field in Azure AD makes sense. Some more background below.

PPIDs

Microsoft use a Pairwise Pseudonymous Identifier (PPID) as the subject claim. This is described in the OpenID Connect core specification, but I'll see if I can explain that in more everyday terms:

Pairwise Pseudonymous Identifier (PPID):

Identifier that identifies the Entity to a Relying Party
that cannot be correlated with the Entity's PPID at another Relying Party.

How the subject claim is returned is exposed in the OpenID Connect metadata. My developer account metadata includes this to indicate that PPIDs are used as the subject claim:

{
  "subject_types_supported": [
    "pairwise"
  ],
}

INTENDED USAGE

PPIDs helps prevent unwelcome user tracking. One example might be a large organization, with departmental boundaries, whose apps are unrelated. It is then a best practice for apps to use different user identifiers, so Microsoft are providing a secure default.

USER RESOURCE MAPPING

When building business software, you typically want a stable yet anonymous user identifier, either an Account ID or PPID. A common option is to store certain domain specific user data outside the identity data, perhaps in a Users table, something like this:

User ID OAuth Subject Subscription Level
123 FyOVI8ZfGEBca1kUsQ1H Gold
245 nOLkJtkepGxnsMtYD245 Silver

The User ID can then be stored against business resources, perhaps in a Purchases table. When your APIs receive access tokens with a subject claim, they can then easily understand which resources are associated to the user:

User ID Purchase ID Status
123 7902345 Pending

PPID SECTORS

PPIDs are typically only useful as the subject claim when a set of related apps receive the same value. This is managed by PPID sectors. This would enable department 1 to use the same stable PPID value for access tokens issued to all of its apps.

SCIM AUTHORIZATION

SCIM clients send User IDs to SCIM endpoints using the Account ID. This type of client could receive the Account ID in access tokens, and optionally also receive a PPID. Using the Account ID does not mean you have higher privileges. That is managed by the SCIM endpoint's authorization, and can use other claims in the access token.

SCIM clients should need a specific scope, such as accounts. In some cases, claims are used to restrict access further. A user might be limited to editing their own info in an edit profile screen, or an administrator may be able to only access users under their area of jurisdiction. Access control lists can be used to restrict access further. Eg a user can view their role but not set it, or set their password but not view it.

Gary Archer
  • 22,534
  • 2
  • 12
  • 24
  • Thanks for the extensive answer. If I could award the bounty twice I would. It went to the earlier and more specific/instructional answer – The Trav Jan 10 '23 at 22:32