SPA braucht sicheren Login? Authorization Code Flow mit PKCE verwenden
Single-Page Applications laufen im Browser.
Das bedeutet: Sie koennen kein Client Secret sicher speichern.
Fuer eine browserbasierte App ist das sichere Muster:
Authorization Code Flow mit PKCE.
PKCE steht fuer Proof Key for Code Exchange.
Unterschied zum Web-App Flow
Der vorherige Trip hat Authorization Code Flow fuer eine serverseitige Web-App verwendet.
Diese App konnte ein client_secret auf dem Server sicher speichern und beim Austausch des Authorization Code gegen Tokens verwenden.
Eine SPA ist anders.
Ihr Code laeuft im Browser des Benutzers. Alles, was in der SPA liegt, kann vom Benutzer eingesehen, kopiert oder veraendert werden.
Deshalb darf eine SPA kein Client Secret verwenden.
Stattdessen verwendet die SPA PKCE:
- die SPA erzeugt einen zufaelligen
code_verifier - beim Sign-in sendet sie nur einen gehashten
code_challenge - spaeter beweist sie den Besitz des urspruenglichen
code_verifier - Microsoft Entra ID stellt Tokens nur aus, wenn der Verifier zur Challenge passt
Das Ziel ist also aehnlich:
Benutzer anmelden -> Authorization Code erhalten -> Code gegen Tokens tauschen -> API aufrufen
Aber der Schutzmechanismus ist anders:
Serverseitige Web-App: Client Secret schuetzt den Code-Austausch
SPA: PKCE schuetzt den Code-Austausch
Dieses Muster wird verwendet, wenn:
- ein Benutzer vorhanden ist
- die App im Browser laeuft
- kein Client Secret geschuetzt werden kann
- die Authentifizierung ueber Microsoft Entra ID erfolgt
- die App delegierten Zugriff auf eine API benoetigt
In diesem Beispiel:
- CloudTrips SPA ist die Browser-Anwendung
- CloudTrips API ist die geschuetzte Resource
- Employee ist der angemeldete Benutzer
Die Authentifizierung erfolgt mit dem OAuth 2.0 Authorization Code Flow mit PKCE. Die Autorisierung wird ueber delegierte Berechtigungen gesteuert.
Architektur
Employee -> CloudTrips SPA -> Microsoft Entra ID -> CloudTrips API
Die SPA leitet den Browser zu Microsoft Entra ID weiter.
Die SPA erhaelt einen Authorization Code.
Die SPA tauscht den Code mit einem PKCE Code Verifier gegen Tokens aus.
Es wird kein Client Secret verwendet.
PKCE Verifier und Challenge
PKCE teilt einen geheimen Nachweis auf zwei Momente auf.
Zuerst erzeugt die SPA eine lange zufaellige Zeichenfolge:
code_verifier=RANDOM_SECRET_CREATED_IN_THE_BROWSER
Die SPA behaelt diesen Wert lokal fuer diesen Sign-in-Versuch.
Danach hasht die SPA diesen Wert mit SHA-256 und kodiert das Ergebnis als base64url:
code_challenge=BASE64URL(SHA256(code_verifier))
code_challenge_method=S256
Der Browser sendet den code_challenge im Authorize Request an Microsoft Entra ID.
Der Browser sendet den code_verifier zu diesem Zeitpunkt noch nicht.
Spaeter, wenn die SPA den Authorization Code erhalten hat, sendet sie den urspruenglichen code_verifier an den Token Endpoint.
Microsoft Entra ID hasht diesen Verifier erneut und prueft, ob das Ergebnis zum frueheren code_challenge passt.
Das ist der zentrale PKCE-Nachweis:
Authorize Request: code_challenge senden
Token Request: code_verifier senden
Entra Pruefung: SHA256(code_verifier) muss zu code_challenge passen
CloudTrips API App erstellen
Erstelle zuerst die Resource-Anwendung.
Gehe zu:
Entra ID > App registrations > New registration
Erstelle eine Anwendung:
Name: CloudTrips-API
Diese App Registration repraesentiert die API, die Access Tokens empfaengt und validiert.

API exponieren
Oeffne in CloudTrips-API:
Expose an API
Setze die Application ID URI:
api://<cloudtrips-api-application-id>
Dieser Bezeichner wird zur Audience fuer Access Tokens, die fuer die CloudTrips API ausgestellt werden.

Delegierten Scope erstellen
Fuege in CloudTrips-API einen delegierten Scope hinzu:
Expose an API > Add a scope
Beispiel:
Scope name: Trips.Read
Who can consent: Admins and users
Admin consent display name: Read CloudTrips trips
User consent display name: Read your CloudTrips trips
State: Enabled
Die CloudTrips API kann spaeter pruefen, ob das eingehende Token diesen Scope enthaelt.

CloudTrips SPA erstellen
Erstelle jetzt die Browser-Client-Anwendung.
Gehe zu:
Entra ID > App registrations > New registration
Erstelle eine Anwendung:
Name: CloudTrips-SPA
Supported account types: Single tenant
Redirect URI platform: Single-page application
Redirect URI: http://localhost:5173/auth/callback
Die Redirect URI ist die Adresse, an die Microsoft Entra ID den Browser nach der Anmeldung zuruecksendet.
In Produktion verwendest du die echte SPA-URL.

SPA Authentication Settings pruefen
Oeffne in CloudTrips-SPA:
Authentication
Pruefe, dass die Plattform ist:
Single-page application
Und dass die Redirect URI lautet:
http://localhost:5173/auth/callback
Erstelle kein Client Secret fuer die SPA.
Eine SPA ist ein Public Client. Jedes Secret im Browser-Code kann von Benutzern gelesen werden.

API-Berechtigung hinzufuegen
Gehe zu:
App registrations > CloudTrips-SPA > API permissions
Waehle:
Add a permission
Waehle:
My APIs > CloudTrips-API > Delegated permissions > Trips.Read
Damit darf die SPA ein Access Token fuer die CloudTrips API im Namen des angemeldeten Benutzers anfordern.

Wenn dein Tenant Administratorfreigabe verlangt, klicke:
Grant admin consent

Authorization Request mit PKCE
Zur Laufzeit wird der Browser weitergeleitet zu:
GET https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize
Die Request-Parameter enthalten:
client_id=CLOUDTRIPS_SPA_CLIENT_ID
response_type=code
redirect_uri=http://localhost:5173/auth/callback
scope=openid profile api://<cloudtrips-api-application-id>/Trips.Read
state=<random-state-value>
code_challenge=<hashed-code-verifier>
code_challenge_method=S256
Die wichtigen PKCE-Werte sind:
| Wert | Bedeutung |
|---|---|
code_verifier |
geheimer Zufallswert, den die SPA erzeugt und bis zum Token Request lokal behaelt |
code_challenge |
gehashter Wert, der aus dem Verifier abgeleitet und im Authorize Request gesendet wird |
code_challenge_method |
S256, also SHA-256 fuer die Challenge |
Microsoft Entra ID speichert die Challenge zusammen mit dem Authorization Code.
Zu diesem Zeitpunkt hat Microsoft Entra ID die Challenge gesehen, aber noch nicht den Verifier.

Callback mit Authorization Code
Nach der Anmeldung leitet Microsoft Entra ID den Browser zurueck an:
http://localhost:5173/auth/callback
Der Callback enthaelt einen Authorization Code.
Die SPA prueft den state Wert und bereitet danach den Token Request vor.
Der Authorization Code allein reicht nicht aus.
Die SPA muss ihn zusammen mit demselben code_verifier einloesen, der vor der Weiterleitung erzeugt wurde.

Code mit Code Verifier austauschen
Die SPA sendet den Authorization Code an Microsoft Entra ID:
POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token
Request Body:
client_id=CLOUDTRIPS_SPA_CLIENT_ID
grant_type=authorization_code
code=AUTHORIZATION_CODE
redirect_uri=http://localhost:5173/auth/callback
code_verifier=ORIGINAL_RANDOM_CODE_VERIFIER
scope=openid profile api://<cloudtrips-api-application-id>/Trips.Read
Es gibt kein client_secret.
Microsoft Entra ID hasht den gesendeten code_verifier und vergleicht ihn mit dem code_challenge aus dem Authorization Request.
Wenn beide Werte passen, stellt Entra Tokens aus.
Wenn der Verifier fehlt, veraendert wurde oder aus einer anderen Browser-Session stammt, schlaegt der Token Request fehl.

Access Token Claims
Die SPA erhaelt ein Access Token fuer die CloudTrips API.
Decodiere das Access Token.
Wichtige Claims:
| Claim | Bedeutung |
|---|---|
aud |
API, die das Token akzeptieren soll |
scp |
Delegierte Berechtigungen, die der SPA 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"
}

Warum PKCE wichtig ist
Ohne PKCE koennte jemand versuchen, einen gestohlenen Authorization Code einzuloesen.
Mit PKCE ist der Authorization Code an den urspruenglichen code_verifier gebunden.
Das bedeutet: Der Token Endpoint verlangt den Nachweis, dass derselbe Browser-Flow, der die Anmeldung gestartet hat, auch den Code einloest.
Unterschied zum serverseitigen Web-App Flow
| Thema | Serverseitige Web-App | SPA mit PKCE |
|---|---|---|
| Client-Typ | Confidential | Public |
| Client Secret | Ja | Nein |
| Token Exchange | Serverseitig | Browser/Public Client |
| Schutz | Client Secret | PKCE Code Verifier |
| Typische Redirect URI | /signin-oidc |
/auth/callback |
Enterprise-Hinweis
Echte Enterprise-Umgebungen haben normalerweise mehrere Stages:
- DEV
- TEST oder STAGE
- PROD
Verwende separate App Registrations pro Umgebung, wenn Redirect URIs, API Audiences oder Consent-Grenzen unterschiedlich sind.
Beispiel:
CloudTrips-SPA-DEV
CloudTrips-SPA-TEST
CloudTrips-SPA-PROD
CloudTrips-API-DEV
CloudTrips-API-TEST
CloudTrips-API-PROD
Das bietet:
- isolierte Redirect URIs
- klarere Token Audiences
- sicherere Consent-Grenzen fuer Produktion
- saubereres Auditing und Troubleshooting