Skip to main content

Microsoft Entra ID

When you're done, your tenant has one enterprise application for the desk:

  • Only people assigned to it can sign in, and when you assign someone you pick one of the desk's roles: Agent, Organization Administrator, Change Manager, your organization's own roles. Platform Administrator is never on the list.
  • The desk keeps that list of roles up to date on the application itself.
  • The desk proves who it is with a certificate it makes and renews itself, so there is no client secret to copy or let expire.
  • Optionally, Entra creates people in the desk as soon as they're assigned, and disables them when they're unassigned (step 6).

Each step below is done in the Microsoft Entra admin center. Under With the Azure CLI the same step is a few commands to copy and paste, one box at a time.

Before you use the Azure CLI

Sign in as an administrator who may grant admin consent. Cloud Shell in the Azure portal (Bash, No storage account required) has the CLI and is signed in already, but it needs an Azure subscription. Without one, install the CLI on your computer and sign in:

az login --tenant <tenant-id> --allow-no-subscriptions

The commands share a few names (DESK, APP, SP). In a new shell, set them again:

DESK=https://desk.example.com
APP=$(az ad app list --display-name "ITSM Engine" --query "[0].appId" -o tsv)
SP=$(az ad sp show --id $APP --query id -o tsv)

1. Create the application​

  1. Enterprise applications → New application → Create your own application. Name it (like ITSM Engine) and pick Integrate any other application you don't find in the gallery (Non-gallery).
  2. Open it under App registrations → All applications. Authentication → Add a platform → Web, with the redirect URI shown on the desk's Identity providers page (https://<your desk>/api/v1/auth/sso/callback).
  3. Token configuration → Add optional claim → ID → email, so the desk gets the email when it differs from the sign-in name.
  4. On Overview, note the Application (client) ID and the Directory (tenant) ID.

[!IMPORTANT] Make it under Enterprise applications as above, not under App registrations → New registration. Both sign people in, but only this one can provision people (step 6).

With the Azure CLI

Your desk's address:

DESK=https://desk.example.com

The application, from the non-gallery template:

APP=$(az rest --method POST --url https://graph.microsoft.com/v1.0/applicationTemplates/8adf8e6e-67b2-4cf2-a259-e3dc5476c621/instantiate --body '{"displayName":"ITSM Engine"}' --query application.appId -o tsv)
echo $APP

Wait half a minute, until Entra knows the new application everywhere. Then the redirect URI and the email claim:

az ad app update --id $APP --web-redirect-uris "$DESK/api/v1/auth/sso/callback" --optional-claims '{"idToken":[{"name":"email","essential":false}]}'

The two IDs for step 3:

echo "Directory (tenant) ID: $(az account show --query tenantId -o tsv)"
echo "Application (client) ID: $APP"

2. Let the desk keep its roles on the application​

The desk writes its roles as app roles of the application through Microsoft Graph, and renews its certificate there. It needs a permission that lets it change only applications it owns, nothing else in your tenant, and it must own its own application.

  1. In the app registration: API permissions → Add a permission → Microsoft Graph → Application permissions → Application.ReadWrite.OwnedBy, then Grant admin consent.
  2. Make the application its own owner. The admin center's Owners page only offers people, so this one is always done with the Azure CLI (below, the last box).
With the Azure CLI

The permission, and the email permission for signing in:

GRAPH=00000003-0000-0000-c000-000000000000
OWNED_BY=$(az ad sp show --id $GRAPH --query "appRoles[?value=='Application.ReadWrite.OwnedBy'].id" -o tsv)
EMAIL=$(az ad sp show --id $GRAPH --query "oauth2PermissionScopes[?value=='email'].id" -o tsv)
az ad app permission add --id $APP --api $GRAPH --api-permissions $OWNED_BY=Role $EMAIL=Scope

Admin consent for both (az ad app permission admin-consent doesn't work in Cloud Shell, so one at a time):

SP=$(az ad sp show --id $APP --query id -o tsv)
az rest --method POST --url https://graph.microsoft.com/v1.0/servicePrincipals/$SP/appRoleAssignments --body "{\"principalId\":\"$SP\",\"resourceId\":\"$(az ad sp show --id $GRAPH --query id -o tsv)\",\"appRoleId\":\"$OWNED_BY\"}"
az ad app permission grant --id $APP --api $GRAPH --scope email

The application as its own owner:

az ad app owner add --id $APP --owner-object-id $SP

If you'd rather not grant the permission, turn off Keep this desk's roles as app roles in the desk, use Copy appRoles JSON, and paste it as appRoles into the registration's Manifest. Do that again whenever roles change, and upload the desk's next certificate yourself each year (The certificate).

3. Set it up in the desk​

Platform → Identity providers → Microsoft Entra ID → Set up:

FieldWhat to enter
Directory (tenant) ID, Application (client) IDFrom step 1.
The desk proves who it is withCertificate. (A client secret works too: make one under Certificates & secrets and enter it with its expiry date.)
Email domainsYour domains, like example.com. People with these emails sign in through Entra ID.
OrganizationOn a desk with several organizations: the one its people work in.
Create people at their first sign-in, Place them inSomeone assigned in Entra who isn't in the desk yet is created at their first sign-in, in this unit.
Keep this desk's roles as app rolesOn, if you did step 2.

Save. The desk makes its key pair and shows the certificate under Certificate.

4. Upload the desk's certificate​

  1. Download certificate in the desk.
  2. In the app registration: Certificates & secrets → Certificates → Upload certificate.
  3. Back in the desk: Check with Entra ID. It says when Entra accepted the certificate, and Roles in Entra ID says when the roles were written (or what Graph refused).
With the Azure CLI

In Cloud Shell, upload the downloaded file first (Manage files → Upload). Then, with its name (--append keeps the credentials already there):

az ad app credential reset --id $APP --cert @itsm-engine-1a2b3c4d.pem --append

5. Choose who may sign in​

In Enterprise applications → your application:

  1. Properties → Assignment required: Yes. Only people assigned to the application can sign in.
  2. Users and groups → Add user/group: pick people or groups, then Select a role. That is the role they get in the desk.
With the Azure CLI

Assignment required:

az ad sp update --id $APP --set appRoleAssignmentRequired=true

Assign someone a role (the role's key, as in the desk's Roles, and their sign-in name):

ROLE=$(az ad app show --id $APP --query "appRoles[?value=='agent'].id" -o tsv)
WHO=$(az ad user show --id [email protected] --query id -o tsv)
az rest --method POST --url https://graph.microsoft.com/v1.0/servicePrincipals/$SP/appRoleAssignedTo --body "{\"principalId\":\"$WHO\",\"resourceId\":\"$SP\",\"appRoleId\":\"$ROLE\"}"

At each sign-in the desk gives the person the roles Entra assigns them, on the whole organization, and takes away roles Entra gave before but no longer does. Where someone works (units and teams) stays in the desk: someone new is placed in the unit you chose, and you move them under Users.

That's all for signing in. Step 6 is optional.

6. Provisioning (optional)​

Without provisioning, someone appears in the desk at their first sign-in, and someone who leaves keeps their account until you disable it. With provisioning, Entra tells the desk straight away:

In EntraIn the desk
Assigned to the applicationCreated in the unit chosen under Place them in, with the role of their assignment, before they ever sign in. Someone already in the desk with that email is linked, not made twice.
Role, name or email changedChanged. Roles given by hand in the desk stay.
Unassigned, disabled or deletedDisabled, and their sessions end. Nothing is deleted: their cases and history stay.
Assigned again, or restoredEnabled again.

Connect Entra to the desk​

  1. In the desk: Identity providers → Microsoft Entra ID → Provisioning → Turn on provisioning. Copy the token: it is shown once.
  2. In Entra: your application → Provisioning → Connect your application (or New configuration). Authentication method Bearer authentication; Tenant URL as shown in the desk (https://<your desk>/scim/v2), and the token as Secret token.
  3. Test connection, then Create.

The token is a secret, so a person pastes it, even when the rest is done with the Azure CLI. Make new token in the desk replaces it (the old one stops working at once); Turn off ends provisioning and leaves everyone as they are.

Map the attributes​

In Entra: your application → Provisioning → Attribute mapping.

  1. Provision Microsoft Entra ID Groups: off. The desk takes people, not groups. Assign a group to the application and its members are provisioned.
  2. Provision Microsoft Entra ID Users:
    • externalId: change the source from mailNickname to objectId. The desk then knows the person by the same id as at sign-in, even before their first one and even when their email changes.
    • Roles: under Show advanced options → Edit attribute list for customappsso, add roles, type String, Multi-Value. Then Add New Mapping: type Expression, expression AppRoleAssignmentsComplex([appRoleAssignments]), target attribute roles. Without it the desk learns their role only when they sign in.
    • Leave userName ← userPrincipalName and emails[type eq "work"].value ← mail as they are. The desk needs an email: the work email, or a userName that is one.
    • Everything else (job title, phone numbers, address, manager …) is ignored. Delete it if you like.
With the Azure CLI

Fetch the mappings Entra made:

JOBS=https://graph.microsoft.com/v1.0/servicePrincipals/$SP/synchronization/jobs
JOB=$(az rest --url $JOBS --query "value[0].id" -o tsv)
az rest --url $JOBS/$JOB/schema > schema.json

Change them as above (groups off, externalId from objectId, roles added):

jq '(.directories[] | select(.name=="customappsso") | .objects[] | select(.name|endswith("enterprise:2.0:User")) | .attributes) += [{name:"roles",type:"String",multivalued:true,mutability:"ReadWrite",anchor:false,caseExact:false,required:false,flowNullValues:false,apiExpressions:[],metadata:[],referencedObjects:[]}]
| (.synchronizationRules[0].objectMappings[] | select(.name|endswith("Groups")) | .enabled) = false
| (.synchronizationRules[0].objectMappings[] | select(.name|endswith("Users")) | .attributeMappings) |= (map(if .targetAttributeName=="externalId" then .source={expression:"[objectId]",name:"objectId",type:"Attribute",parameters:[]} else . end)
+ [{targetAttributeName:"roles",flowType:"Always",flowBehavior:"FlowWhenChanged",matchingPriority:0,exportMissingReferences:false,defaultValue:null,source:{expression:"AppRoleAssignmentsComplex([appRoleAssignments])",name:"AppRoleAssignmentsComplex",type:"Function",parameters:[{key:"source",value:{expression:"[appRoleAssignments]",name:"appRoleAssignments",type:"Attribute",parameters:[]}}]}}])' schema.json > mapped.json

Save them in Entra:

az rest --method PUT --url $JOBS/$JOB/schema --body @mapped.json --headers Content-Type=application/json

Start it​

  1. Provisioning → Provision on demand: pick one assigned person and check they appear in the desk.
  2. Start provisioning. The scope is Sync only assigned users and groups; Entra then provisions every 40 minutes.
With the Azure CLI
az rest --method POST --url $JOBS/$JOB/start

Provisioning never touches a Platform Administrator, someone who works in another organization, or someone named under Still sign in with a password in case Entra can't be reached; Entra's provisioning log says why. Creating or enabling someone takes a seat of the licence: with none left, Entra's log says so and nobody already active is affected. What the desk refused last is shown under Provisioning, and every change is in the audit log as made by Microsoft Entra ID provisioning.

The certificate​

The desk makes an RSA key pair and a certificate valid for a year. The private key stays in the desk, encrypted, and is never shown; only the certificate is uploaded to Entra. The desk signs in to Entra with a signed client assertion (private_key_jwt), never a secret.

A month before the certificate runs out, the desk makes the next one and adds it to the application itself through Microsoft Graph, proving itself with the current one (the permission from step 2). Once the new one has worked, the old one is removed. Nobody has to do anything, and Renew now does it at once.

Without the Graph permission, the next certificate waits under Certificate with Download next certificate. Upload it like the first one; the desk takes it into use as soon as Entra accepts it, and the current one keeps working until then.

Access packages​

Entra ID Governance's access packages work as they are: add the enterprise application to a catalog as a resource, and put one of its roles in an access package (Service desk agents → ITSM Engine, role Agent). People who get the package get the role, with the package's approval, expiry and access reviews. When the package ends, so does the role: within one provisioning cycle with step 6, otherwise at their next sign-in. With Assignment required they can't sign in at all.

Sign-in and provisioning read the same thing, the person's assignment on the application, so they never disagree: whichever reaches the desk first sets the role.

A role made in the desk shows in the catalog after the resource is refreshed there.

Troubleshooting​

On the sign-in pageWhy
That account isn't from your organization's directoryThe account is from another tenant than the one set up.
Your organization hasn't given you accessAssigned without a role (Default Access), and no role given in the desk.
There's no free seat for someone newEvery seat of the licence is used.
Your identity provider didn't complete the sign-inEntra refused (often: not assigned, or a wrong redirect URI); the audit log has Entra's message.
On the Identity providers pageWhy
Entra ID refused the certificateIt isn't uploaded to the application (step 4), or it was removed there.
The next certificate isn't on the application yetThe desk couldn't add it through Graph (step 2). Upload it by hand.
Provisioning: Last refusedWhat the desk refused last, as Entra's provisioning log shows it too.
In Entra's provisioningWhy
The Provisioning page says it isn't supported, Get started greyed outThe application was made under App registrations. Make one as in step 1, set it up in the desk again, and upload its certificate.
Test connection: 401The token is wrong or was replaced; make a new one in the desk.
A person fails with 403A Platform Administrator, someone in another organization, or no free seat: the error says which.
A person fails with 409Someone else is provisioned with that userName, or someone else in the desk has that email.
Saving the mappings: missing required parameter 'source'The roles mapping's parameter must be named source.