5 minute read

Whether you’re trying to handle authentication or doing something else, you might need to obtain the current tenant ID or user’s object ID in Entra. There are a few ways of doing this from the client and not all of them are well known (or even possible).

The motivation behind this is that people seem to do a lot of unnecessary API calls which then slow down the application and add unnecessary complexity to the code. You should always try to pull the data from memory rather than making an asynchronous API call.

As some of these properties are not documented (or included in types), it may be a challenge to access them.

I am not really happy from the inconsistencies between XRM and PCF APIs. I can imagine some reasons behind it - like it unifies Canvas, Model driven and Power Pages, but that’s not really what’s behind the scenes. We will take a deeper look into PCFs in Power Pages another time.

Before we get into the specifics, you might ask - what is any of this good for? Well, for example, if you want to call a 3rd party Entra protected API (or even Microsoft Graph) from within your PCF, you need to authenticate. For authentication, you should use MSAL (or any other OAuth2/OIDC compliant client) and for constructing the correct authority URL (and accessing metadata) you need the tenant ID (like https://login.microsoftonline.com/<tenant-id>/). For silent SSO to provide login_hint parameter, you need the user principal name. We will go deeper into authentication topic later.

Obtaining user’s ID (systemuserid)

This is probably the most straightfroward operation since this identifier is exposed everywhere. You can use it to resolve the current user via an API call

XRM

const systemuserid = Xrm.Utility.getGlobalContext().userSettings.userId;
// {B71109E2-3BB7-4A62-AAD1-072214FAC31C}

PCF

const systemuserid = context.userSettings.userId;
// {B71109E2-3BB7-4A62-AAD1-072214FAC31C}

Web API

Either execute this either via Xrm.WebApi.execute, in cookie-authenticated session or with a Bearer token. WhoAmI reference

GET https://<instance>.crm4.dynamics.com/api/data/v9.1/WhoAmI

Response:

{
  "@odata.context": "https://<instance>.crm4.dynamics.com/api/data/v9.1/$metadata#Microsoft.Dynamics.CRM.WhoAmIResponse",
  // ...
  "UserId": "b71109e2-3bb7-4a62-aad1-072214fac31c",
  // ...
}

Obtaining Entra tenant ID

XRM

const tenantId = Xrm.Utility.getGlobalContext().organizationSettings.organizationTenant;
// 67266d43-8de7-494d-9ed8-3d1bd3b3a764

PCF

const tenantId = context.orgSettings.tenantId;
// 67266d43-8de7-494d-9ed8-3d1bd3b3a764

Web API

RetrieveCurrentOrganization reference

GET https://<instance>.crm4.dynamics.com/api/data/v9.1/RetrieveCurrentOrganization(AccessType=Microsoft.Dynamics.CRM.EndpointAccessType'Default')

Response:

{
  "@odata.context": "https://hajekj.crm4.dynamics.com/api/data/v9.1/$metadata#Microsoft.Dynamics.CRM.RetrieveCurrentOrganizationResponse",
  "Detail": {
    // ...
    "TenantId": "67266d43-8de7-494d-9ed8-3d1bd3b3a764",
    // ...
  }
}

Obtaining Entra user’s object ID

XRM

At the moment, there doesn’t seem to be a way to pull user’s object ID from XRM directly.

// Unsupported way, you can check this value and fallback to the Web API call below for backup
const aadObjectId = window.__preload.aadObjectId;
// d8b828cf-6af7-4673-b11e-7de2dc05236f

PCF

const aadObjectId = context.userSettings.aadObjectId;
// d8b828cf-6af7-4673-b11e-7de2dc05236f

Web API

GET https://<instance>.crm4.dynamics.com/api/data/v9.1/systemusers(<systemuserid>)?$select=azureactivedirectoryobjectid

Response:

{
  "@odata.context": "https://hajekj.crm4.dynamics.com/api/data/v9.1/$metadata#systemusers(azureactivedirectoryobjectid)/$entity",
  // ...
  "azureactivedirectoryobjectid": "d8b828cf-6af7-4673-b11e-7de2dc05236f"
}

Obtaining Entra user’s User Principal Name

You need this for example when doing SSO and want to provide login_hint for silent login.

XRM

Unsprisingly, just like with Entra user’s object ID, this is not directly supported. This value contains the correct information even in B2B scenarios (see Web API for more on B2B UPNs).

// Unsupported way, you can check this value and fallback to the Web API call below for backup
const loginHint = window.__preload.aadLoginHint;
// jan.hajek@thenetw.org

PCF

Unfortunately, it is not available either, so you have to use the method mentioned above in XRM or call the Web API.

Web API

You should be using windowsliveid which corresponds to the UPN, whereas internalemailaddress is user’s primary e-mail address. Retrieving both is necessary for B2B guest scenarios, where windowsliveid will contain #EXT# which won’t work for loginHint and you will have to try with internalemailaddress (which will work in most cases). With organizations whose UPN doesn’t match primary email address (for whatever reason), you will want to use windowsliveid.

GET https://<instance>.crm4.dynamics.com/api/data/v9.1/systemusers(<systemuserid>)?$select=internalemailaddress,windowsliveid

Response:

{
  "@odata.context": "https://hajekj.crm4.dynamics.com/api/data/v9.1/$metadata#systemusers(internalemailaddress,windowsliveid)/$entity",
  // ...
  "windowsliveid": "jan.hajek@thenetw.org",
  "internalemailaddress": "jan.hajek@thenetw.org"
}

Obtaining current environment ID

This corresponds to the ID you use in calling the BAP API for example.

XRM

const tenantId = Xrm.Utility.getGlobalContext().organizationSettings.bapEnvironmentId;
// 2b780552-3247-473b-ba66-e3681799d66f

PCF

You cannot retrieve this information through PCF’s context, use the XRM way.

Web API

RetrieveCurrentOrganization reference

GET https://<instance>.crm4.dynamics.com/api/data/v9.1/RetrieveCurrentOrganization(AccessType=Microsoft.Dynamics.CRM.EndpointAccessType'Default')

Response:

{
  "@odata.context": "https://hajekj.crm4.dynamics.com/api/data/v9.1/$metadata#Microsoft.Dynamics.CRM.RetrieveCurrentOrganizationResponse",
  "Detail": {
    // ...
    "EnvironmentId": "2b780552-3247-473b-ba66-e3681799d66f",
    // ...
  }
}

Have I missed a way?

Let me know! I am curious about any other ways you might use to obtain these values.

To submit comments, go to GitHub Discussions.