Projekt · Entra ID

End-to-End IAM, del 2: Provisionering mot Entra ID med Microsoft Graph

By Andreas Krisby 2026-07-26 4 min read

Det här är del 2 i serien om end-to-end-iam. Del 1 gick igenom varför Elytra och Ascendra är helt separata system, och hur en händelselogg (en utkorg) håller dem synkade. Den här delen handlar om vad som händer när Ascendra väl vet att en anställning ändrats: hur den faktiskt skapar, uppdaterar och inaktiverar riktiga användarkonton i Entra ID.

Första försöket: SCIM var fel väg

SCIM (System for Cross-domain Identity Management) är en vedertagen standard för att provisionera användare mellan system, och min första tanke var att använda den. Det visade sig vara fel väg för det här scenariot.

SCIM fungerar genom att målsystemet exponerar en inkommande slutpunkt som en extern part provisionerar mot. Entra ID gör precis tvärtom här: det är Entra ID som är målkatalogen. Det finns ingen inkommande SCIM-slutpunkt i Entra ID att skicka användare till. SCIM används i stället av Entra ID åt andra hållet, när Entra själv provisionerar användare vidare till andra molntjänster (till exempel en tredjepartsapp som får sina konton skapade av Entra).

Eftersom Ascendra ska skriva in i Entra ID, inte ta emot data från det, var SCIM aldrig rätt verktyg här.

Rätt väg: Microsoft Graph

Microsoft Graph är Microsofts gränssnitt för Entra ID och resten av Microsoft 365. Det är ett gränssnitt som andra program pratar med för att läsa och ändra data, till exempel för att skapa en användare, uppdatera dennes attribut eller inaktivera ett konto. Varje sådan begäran är ett Graph-anrop.

Ascendra autentiserar sig mot Microsoft Graph med Client Credentials-flödet, ett standardiserat sätt (definierat av protokollet OAuth 2.0) för program att autentisera sig mot varandra utan att en människa loggar in. I korthet:

  1. Ascendra skickar sitt klient-ID och sin klienthemlighet (en hemlig nyckel) till Entra ID:s slutpunkt för att hämta en token.
  2. Entra ID svarar med en token, giltig en begränsad tid, som bevisar att Ascendra fått rätt att göra anrop.
  3. Ascendra bifogar den token i varje efterföljande Graph-anrop, tills den behöver förnyas.

Det finns aldrig en inloggad person i det här flödet. Behörigheterna tillhör appen själv, inte en användare, vilket kallas applikationsbehörigheter, till skillnad från delegerade behörigheter som ärver rättigheterna från den som är inloggad.

Appregistreringen i Entra ID

För att det här ska fungera behövde jag registrera Ascendra som en app i Entra ID, med en specifik uppsättning inställningar:

  • Bara vår egen klientorganisation: appen får bara användas mot vår egen Entra ID-klientorganisation, inte av andra organisationer. Det finns ingen anledning att tillåta flera klientorganisationer här.
  • Ingen inloggningsomdirigering: en sådan adress behövs bara vid interaktiv inloggning. Eftersom Client Credentials-flödet aldrig visar en inloggningsruta, behövs ingen.
  • User.ReadWrite.All: behörighet att läsa och skriva alla användarkonton i klientorganisationen. Det här är den behörighet som faktiskt gör provisioneringen möjlig.
  • Organization.Read.All: behörighet att läsa organisationsinformation, till exempel vilka domäner som är verifierade (mer om varför nedan).
  • Administratörsgodkännande: eftersom det här är kraftfulla behörigheter som gäller för hela klientorganisationen, måste en administratör uttryckligen godkänna dem innan appen får använda dem. Den här typen av behörighet går inte att smyga igenom.
  • Klienthemlighet: den hemliga nyckel Ascendra använder för att bevisa sin identitet i steg 1 ovan.

Den här kombinationen är medvetet snäv. Ascendra får precis den räckvidd den behöver för att hantera användarkonton, varken mer eller mindre.

Vad Ascendra faktiskt skickar

När en händelse kommer in från utkorgen (se del 1) översätter Ascendra den till konkreta Graph-anrop:

  • employee.created → ett nytt användarobjekt skapas i Entra ID med rätt namn, avdelning och kontostatus.
  • employee.updated → befintliga attribut på användaren uppdateras.
  • employee.activated → kontot sätts till aktivt (accountEnabled = true).
  • employee.terminated → kontot inaktiveras (accountEnabled = false).

Det låter enkelt, men just det sista steget, att sätta accountEnabled korrekt, visade sig vara källan till det allvarligaste felet i hela projektet. Den beskrivs i detalj i del 3.

UPN och e-post är inte samma sak

Ett problem som dök upp direkt var att min Entra ID-klientorganisation bara hade sin standarddomän verifierad, inte en egen anpassad domän. userPrincipalName (UPN) är det inloggningsnamn en användare faktiskt loggar in med i Entra ID, och det måste ligga på en domän som klientorganisationen har verifierat äganderätt till.

Lösningen blev att särskilja de två fälten:

  • userPrincipalName sätts till den verifierade domänen, eftersom Entra ID kräver det för inloggning.
  • mail behåller användarens riktiga, faktiska e-postadress.

Det är också hur många företag faktiskt löser det i praktiken: inloggningsnamnet och adressen kollegor mejlar till är inte alltid identiska, även om de ofta råkar se likadana ut.

Vad det här bygger på

Provisioneringen mot Entra ID vilar alltså på tre saker som hänger ihop: en snävt avgränsad appregistrering med bara de behörigheter som faktiskt behövs, ett autentiseringsflöde byggt för program snarare än människor, och en tydlig regel för hur data mappas mellan HR-systemets syn på en person och Entra ID:s krav på inloggningsidentiteter.

Nästa del i serien går igenom vad som händer när det här inte räcker, när ett Graph-anrop misslyckas, en händelse tappas bort, eller ett fel gör att fel status skickas till Entra, och hur reconciliation och JML-flödet fångar upp det.

Entra ID – Granskningslogg som visar att Ascendra skapat och uppdaterat ett riktigt användarkonto