API braucht Benutzerberechtigungen? Delegierten Scope exponieren
APIs sollten Access Tokens nicht nur akzeptieren, weil das Token technisch gueltig ist.
Sie sollten auch pruefen, was der angemeldete Benutzer tun darf.
Fuer benutzerbasierten API-Zugriff ist das Microsoft-Entra-Muster:
Einen delegierten Scope exponieren.
Dieses Muster wird verwendet, wenn:
- ein Benutzer vorhanden ist
- eine App eine API im Namen dieses Benutzers aufruft
- die API Benutzerberechtigungen pruefen muss
- die Authentifizierung ueber Microsoft Entra ID erfolgt
- die Autorisierung auf dem
scpClaim im Access Token basiert
In diesem Beispiel:
- CloudTrips API ist die geschuetzte Resource
- CloudTrips Client ist eine benutzerorientierte Client-App
- Employee ist der angemeldete Benutzer
Der Client kann eine Web-App, SPA, CLI, mobile App oder Desktop-App sein.
Der wichtige Teil ist immer gleich:
Client fordert Scope an -> Entra stellt Access Token aus -> API validiert aud und scp
Delegierter Scope vs App Role
Ein delegierter Scope beschreibt, was eine Client-App im Namen eines angemeldeten Benutzers tun darf.
In Tokens erscheinen delegierte Berechtigungen in:
scp
Beispiel:
{
"scp": "Trips.Read"
}
Eine App Role beschreibt rollenbasierte Autorisierung fuer eine Anwendung, einen Benutzer oder eine Gruppe.
In Tokens erscheinen App Roles in:
roles
Verwende delegierte Scopes, wenn die API-Entscheidung von der Berechtigung abhaengt, die der Client fuer den Benutzer angefordert hat.
Verwende App Roles, wenn die App-Entscheidung von der Rolle abhaengt, die dem Benutzer oder der Gruppe zugewiesen ist.
Dasselbe User Token kann beide Claims enthalten:
{
"scp": "Trips.Read",
"roles": ["Trip.Approver"]
}
Dann beantworten die Claims unterschiedliche Fragen:
scp
Frage:
Darf dieser Client diese API-Operation fuer den angemeldeten Benutzer aufrufen?
Beispiel:
Read Endpoint erlauben, wenn scp Trips.Read enthaelt.
roles
Frage:
Welche Rolle hat dieser Benutzer oder diese Gruppe in der App?
Beispiel:
Approval-Funktionen anzeigen, wenn roles Trip.Approver enthaelt.
Fuer APIs ist ein haeufiges Muster:
aud pruefen -> Token ist fuer diese API
scp pruefen -> Client hat delegierte Berechtigung
roles pruefen -> Benutzer hat erforderliche Business-Rolle, wenn der Endpoint sie braucht
Dieser Trip konzentriert sich vor allem auf delegierte Scopes und den scp Claim.
CloudTrips API App erstellen
Erstelle zuerst die Resource-Anwendung.
Gehe zu:
Entra ID > App registrations > New registration
Erstelle eine Anwendung:
Name: CloudTrips-API
Supported account types: Single tenant
Diese App Registration repraesentiert die API, die Access Tokens empfaengt und validiert.

Application ID URI setzen
Oeffne in CloudTrips-API:
Expose an API
Setze die Application ID URI:
api://<cloudtrips-api-application-id>
Dieser Wert wird zur API Audience.
Das Access Token sollte diesen Wert spaeter im aud Claim enthalten.

Delegierten Scope hinzufuegen
Waehle in CloudTrips-API:
Add a scope
Erstelle einen delegierten Scope:
Scope name: Trips.Read
Who can consent: Admins and users
Admin consent display name: Read CloudTrips trips
Admin consent description: Allows the app to read CloudTrips trips for the signed-in user.
User consent display name: Read your CloudTrips trips
User consent description: Allows the app to read your CloudTrips trips.
State: Enabled
Damit definierst du eine Benutzerberechtigung, die Client-Apps anfordern koennen.

Nach dem Speichern erscheint der Scope unter:
Scopes defined by this API
Der vollstaendige Berechtigungswert ist:
api://<cloudtrips-api-application-id>/Trips.Read

Client App erstellen
Erstelle jetzt eine Client-App, die den Scope anfordern wird.
Gehe zu:
Entra ID > App registrations > New registration
Erstelle eine Anwendung:
Name: CloudTrips-Client
Supported account types: Single tenant
Die genaue Plattform haengt vom App-Typ ab.
In diesem Trip soll der Client nur zeigen, dass eine benutzerorientierte App den delegierten Scope anfordern kann.

API-Berechtigung hinzufuegen
Oeffne in CloudTrips-Client:
API permissions > Add a permission
Waehle:
My APIs > CloudTrips-API > Delegated permissions > Trips.Read
Damit darf die Client-App Trips.Read im Namen des angemeldeten Benutzers anfordern.

Consent erteilen
Wenn dein Tenant Administratorfreigabe verlangt, klicke:
Grant admin consent
Nach dem Consent sollte der Berechtigungsstatus zeigen, dass Consent fuer den Tenant erteilt wurde.

Access Token anfordern
Der Client fordert ein Access Token mit dem vollstaendigen Scope-Wert an:
api://<cloudtrips-api-application-id>/Trips.Read
Der genaue OAuth Flow haengt vom Client-Typ ab:
| Client-Typ | Typischer Flow |
|---|---|
| Serverseitige Web-App | Authorization Code Flow |
| SPA | Authorization Code Flow mit PKCE |
| CLI oder Device | Device Code Flow |
| Mobile oder Desktop-App | Authorization Code Flow mit PKCE |
Der wichtige Request-Wert ist der Scope:
scope=openid profile api://<cloudtrips-api-application-id>/Trips.Read
Access Token pruefen
Decodiere das Access Token.
Fuer delegierten API-Zugriff pruefst du diese Claims:
| Claim | Bedeutung |
|---|---|
aud |
API, die das Token akzeptieren soll |
scp |
Delegierte Berechtigungen, die dem Client erteilt wurden |
sub |
Stabiler Benutzerbezeichner fuer diese App |
tid |
Tenant ID |
iss |
Token Issuer |
Der wichtige Nachweis in diesem Trip ist:
{
"aud": "api://<cloudtrips-api-application-id>",
"scp": "Trips.Read"
}
Token in der API validieren
Die API sollte mehr pruefen als nur die Token-Signatur.
Validiere mindestens:
- Signatur
- Issuer
- Audience
- Ablaufzeit
- erforderlichen delegierten Scope
Beispiel-Logik:
const audiences = Array.isArray(claims.aud) ? claims.aud : [claims.aud];
if (!audiences.includes('api://<cloudtrips-api-application-id>')) {
throw new Error('Invalid audience');
}
const scopes = String(claims.scp ?? '').split(' ');
if (!scopes.includes('Trips.Read')) {
throw new Error('Missing required scope');
}
Wenn das Token gueltig ist und scp=Trips.Read enthaelt, gibt die API die geschuetzten Daten zurueck.
Scopes und Rollen in User Tokens vergleichen
Scopes und Rollen werden oft verwechselt, weil beide in User Access Tokens vorkommen koennen.
Sie sind nicht dasselbe.
scp kommt aus delegierten API-Berechtigungen.
Der Claim sagt, welche Berechtigung die Client-App fuer diesen API-Aufruf erhalten hat.
roles kommt aus App-Role-Zuweisungen.
Der Claim sagt, welche Rolle der angemeldete Benutzer oder seine Gruppe in der Anwendung hat.
Verwende scp fuer API-Berechtigungsgrenzen:
Darf dieser Client GET /trips fuer diesen Benutzer aufrufen?
Erforderlicher Claim: scp enthaelt Trips.Read
Verwende roles fuer App- oder Business-Autorisierung:
Darf dieser Benutzer eine Reise genehmigen?
Erforderlicher Claim: roles enthaelt Trip.Approver
Fuer eine einfache Read API kann scp=Trips.Read ausreichen.
Fuer einen sensiblen Workflow pruefst du beide:
scp enthaelt Trips.Write
roles enthaelt Trip.Manager
Die API sollte trotzdem Tokens ablehnen, die zwar gueltige JWTs sind, aber nicht fuer diese API gueltig sind.
Lehne den Request ab, wenn:
audfuer eine andere API istscpnichtTrips.Readenthaelt- das Token abgelaufen ist
- das Token aus dem falschen Tenant stammt
- die Token-Signatur nicht verifiziert werden kann
Beispiele:
403 Invalid audience
403 Missing required scope: Trips.Read
401 Access token is expired
Enterprise-Hinweis
Delegierte Scopes sind Teil des API-Vertrags.
Benenne sie sorgfaeltig.
Gute Scope-Namen beschreiben die API-Berechtigung:
Trips.Read
Trips.Write
Trips.Approve
Vermeide breite Scopes, wenn eine engere Berechtigung moeglich ist.
Fuer Produktion solltest du dokumentieren:
- welche Clients welchen Scope anfordern duerfen
- ob User Consent erlaubt ist
- wann Admin Consent erforderlich ist
- welche API-Endpunkte welche Scopes verlangen
- wie fehlende Scopes geloggt und untersucht werden
So wird Autorisierung leichter auditierbar und sicherer zu aendern.