Entwickler-Leitfaden · OpenID Connect

CodeB-Anmeldung in Ihre App einbauen.

Diese Seite führt Sie durch alles, was Sie brauchen, um den OpenID-Connect-Identity-Provider von CodeB von einer Drittanbieter-Website aus zu konsumieren — PKCE-Setup, Auth-Code-Tausch, JWT-Validierung, Refresh-Handhabung und Logout. Kopierfertige Beispiele in Vanilla-JavaScript und Node, plus ein curl-Durchlauf für Backend-Bastler.

Der gesamte IdP ist standardkonform zu OIDC Core 1.0. Wenn Sie bereits eine Library wie oidc-client-ts, openid-client (Node), Authlib (Python) oder die eingebaute OpenIdConnectAuthentication aus .NET verwenden — richten Sie sie auf die Discovery-URL und konfigurieren Sie Ihre Client-ID. Die meisten Schritte unten kollabieren dann zu einem Config-Block.

Inhalt
  1. Voraussetzungen
  2. Anwendung registrieren
  3. Endpoints entdecken
  4. Der Anmelde-Flow
  5. Vollständiger Code — Vanilla-JS
  6. Vollständiger Code — Node / Express
  7. curl-Durchlauf
  8. ID-Token validieren
  9. Refresh + Logout
  10. Token-Widerruf
  11. Authentifizierungs-Faktor (amr / acr)
  12. Key-Rotation-Runbook
  13. Fehlersuche
  14. Schnellreferenz

1. Voraussetzungen

2. Anwendung registrieren

CodeB verlangt, dass jede Relying Party vorregistriert ist — die Standard-OIDC-Haltung (RFC 6749 §3.1.2.1). Die Vorregistrierung verriegelt, welche redirect_uri-Werte der IdP akzeptiert, und genau das verhindert, dass ein Angreifer die Auth-Codes Ihrer Nutzer abfängt.

Der Betreiber fügt Ihren Client in App_Data/<tenant>/oidc/clients.json ein. Die Datei ist pro Mandant und wird bei jeder Änderung heiß nachgeladen — kein IIS-Recycle nötig. Beispiel:

{ "clients": [ { "client_id": "nextcloud", "redirect_uris": ["https://cloud.example.com/index.php/apps/user_oidc/code"], "description": "Acme Nextcloud (user_oidc-App)" }, { "client_id": "acme-portal", "redirect_uris": [ "https://app.acme.com/oauth/callback", "https://staging.acme.com/oauth/callback" ], "description": "Acme Support-Portal (prod + staging)" } ] }

Wenn Sie den Host nicht selbst betreiben, schreiben Sie an info@aloaha.com mit Ihrem Anwendungsnamen, der exakten Callback-URL (HTTPS, außer loopback) und ob Sie Test- vs. Produktions-Redirects benötigen. Alle CodeB-Clients sind öffentliche PKCE-only-Clients — kein Client-Secret zu verwalten.

Der eingebaute codeb-admin-Client ist immer verfügbar und an https://<tenant>/oidc-callback.html gebunden — das ist, was die Admin-UI antreibt. Sie können ihn nicht in clients.json überschreiben oder entfernen.

Für Experimente gegen Ihren eigenen Mandanten ist der eingebaute Client codeb-admin mit der Redirect-URI https://<ihr-host>/oidc-callback.html vorregistriert — das nutzen die CodeB-Admin-Seiten. Verwenden Sie ihn nicht für Drittanbieter-Produktions-Integrationen; fordern Sie Ihre eigene Client-ID an.

3. Endpoints entdecken

Der IdP veröffentlicht alles Nötige unter der Standard-Well-known-URL:

curl https://www.aloaha.com/.well-known/openid-configuration

Antwort (gekürzt):

{ "issuer": "https://www.aloaha.com", "authorization_endpoint": "https://phone.aloaha.com/oidc.ashx?action=authorize", "token_endpoint": "https://phone.aloaha.com/oidc.ashx?action=token", "userinfo_endpoint": "https://phone.aloaha.com/oidc.ashx?action=userinfo", "jwks_uri": "https://www.aloaha.com/.well-known/jwks.json", "end_session_endpoint": "https://phone.aloaha.com/oidc.ashx?action=end_session", "response_types_supported": ["code"], "id_token_signing_alg_values_supported": ["RS256"], "code_challenge_methods_supported": ["S256"], "grant_types_supported": ["authorization_code", "refresh_token"], "scopes_supported": ["openid", "profile", "email", "groups", "phone", "address"], "token_endpoint_auth_methods_supported": ["none"] }

Die meisten Libraries holen sich das einmal beim Start und cachen es. Holen Sie es neu, wenn Sie bei der Token-Validierung kid-Mismatches zu sehen beginnen (Betreiber hat den Key rotiert).

4. Der Anmelde-Flow

Standard-Authorization-Code mit PKCE. Vier bewegliche Teile: Ihr Frontend, Ihr Backend, der Browser des Nutzers und der CodeB-IdP.

1

PKCE-Paar im Frontend erzeugen

Zufälliger 32-Byte-code_verifier, base64url-codiert. code_challenge ist der SHA-256 des Verifiers, ebenfalls base64url. Verifier in sessionStorage ablegen, damit die Callback-Seite ihn wiederfindet.

2

Nutzer zu /authorize umleiten

Mit Ihrer client_id, Ihrer redirect_uri, angefragten Scopes (immer openid einschließen), einem zufälligen state-Token, dem code_challenge und code_challenge_method=S256.

3

CodeB fordert den Nutzer zur Anmeldung auf

Der Nutzer landet auf /login.html, tippt seinen CodeB-Benutzernamen + Passwort (clientseitig zu HA1 gehasht; das Klartext-Passwort verlässt nie den Browser). Bei Erfolg leitet CodeB zurück auf Ihre redirect_uri mit ?code=…&state=….

4

State validieren, Code tauschen

Frontend prüft, dass state mit dem gesendeten Wert übereinstimmt. Dann postet entweder das Frontend (Public Client) oder das Backend (Confidential Client) den Code + PKCE-Verifier an /token und erhält access_token, id_token, refresh_token.

5

ID-Token verifizieren, Nutzer einloggen

JWT-Signatur gegen die JWKS des IdP validieren, iss, aud, exp, nonce prüfen. Der sub-Claim ist die Nutzer-ID; role ist admin/user/siponly/guest.

5. Vollständiger Code — Vanilla-JS (Public SPA Client)

Für eine Single-Page-App, die den gesamten Flow clientseitig erledigt. Zwei Dateien: ein Launcher und ein Callback-Handler.

Launcher (der Button, der die Anmeldung startet)

// Auf der Seite mit Ihrem "Mit CodeB anmelden"-Button: async function signInWithCodeB() { // 1. PKCE-Verifier + Challenge erzeugen const verifier = b64url(crypto.getRandomValues(new Uint8Array(48))); const challenge = b64url(new Uint8Array( await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier)))); const state = b64url(crypto.getRandomValues(new Uint8Array(16))); // 2. Beide ablegen, damit die Callback-Seite sie wiederfindet sessionStorage.setItem('oidc.verifier', verifier); sessionStorage.setItem('oidc.state', state); // 3. Redirect zu /authorize const params = new URLSearchParams({ response_type: 'code', client_id: 'YOUR_CLIENT_ID', redirect_uri: 'https://your-app.com/oidc/callback', scope: 'openid profile email', state, code_challenge: challenge, code_challenge_method: 'S256' }); location.assign('https://phone.aloaha.com/oidc.ashx?action=authorize&' + params); } function b64url(bytes) { return btoa(String.fromCharCode(...bytes)) .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); }

Callback-Handler (die Seite, auf die CodeB zurückleitet)

// Unter https://your-app.com/oidc/callback (async () => { const url = new URL(location.href); const code = url.searchParams.get('code'); const state = url.searchParams.get('state'); const saved = sessionStorage.getItem('oidc.state'); const verif = sessionStorage.getItem('oidc.verifier'); // KRITISCH: state erzwingen. Fehlt ODER passt nicht -> abbrechen. if (!code || !saved || state !== saved || !verif) { document.body.textContent = 'Anmeldung fehlgeschlagen (bad state).'; return; } sessionStorage.removeItem('oidc.state'); sessionStorage.removeItem('oidc.verifier'); // Code gegen Tokens tauschen const body = new URLSearchParams({ grant_type: 'authorization_code', code, redirect_uri: 'https://your-app.com/oidc/callback', client_id: 'YOUR_CLIENT_ID', code_verifier: verif }); const r = await fetch('https://phone.aloaha.com/oidc.ashx?action=token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body }); const tok = await r.json(); if (!r.ok || !tok.access_token) { document.body.textContent = 'Token-Tausch fehlgeschlagen: ' + (tok.error_description || tok.error); return; } // Sie haben jetzt: // tok.access_token -- als Authorization: Bearer an Ihre API senden // tok.id_token -- JWT, das den Nutzer identifiziert (sub, role, Profil-Claims) // tok.refresh_token -- später gegen frisches access_token tauschen // tok.expires_in -- Sekunden bis access_token abläuft (typ. 3600) sessionStorage.setItem('app.access_token', tok.access_token); sessionStorage.setItem('app.refresh_token', tok.refresh_token); sessionStorage.setItem('app.expires_at', Math.floor(Date.now()/1000) + tok.expires_in); location.replace('/'); })();

Public Clients müssen PKCE verwenden. Ohne PKCE kann jeder, der die Redirect-URL abfängt, den Code gegen Tokens tauschen. Wir akzeptieren den authorization_code-Grant nicht ohne code_verifier.

6. Vollständiger Code — Node / Express (Confidential Client)

Für ein Backend, das den Token-Tausch serverseitig erledigt — das empfohlene Muster, wenn Sie Ihren eigenen Server kontrollieren. Nutzt das npm-Paket openid-client, das Discovery, PKCE, Token-Validierung und Refresh handhabt.

// npm install openid-client express express-session import express from 'express'; import session from 'express-session'; import { Issuer, generators } from 'openid-client'; const app = express(); app.use(session({ secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: true })); const codeb = await Issuer.discover('https://www.aloaha.com'); const client = new codeb.Client({ client_id: process.env.CODEB_CLIENT_ID, client_secret: process.env.CODEB_CLIENT_SECRET, // nur für Confidential Clients redirect_uris: ['https://your-app.com/oidc/callback'], response_types: ['code'] }); app.get('/login', (req, res) => { const verifier = generators.codeVerifier(); const state = generators.state(); req.session.pkce = verifier; req.session.state = state; res.redirect(client.authorizationUrl({ scope: 'openid profile email', code_challenge: generators.codeChallenge(verifier), code_challenge_method: 'S256', state })); }); app.get('/oidc/callback', async (req, res) => { const params = client.callbackParams(req); const tokenSet = await client.callback( 'https://your-app.com/oidc/callback', params, { code_verifier: req.session.pkce, state: req.session.state } ); req.session.user = tokenSet.claims(); // sub, role, email, ... req.session.tokens = { access_token: tokenSet.access_token, refresh_token: tokenSet.refresh_token, expires_at: tokenSet.expires_at }; res.redirect('/'); }); app.get('/me', (req, res) => { if (!req.session.user) return res.status(401).end(); res.json(req.session.user); });

7. curl-Durchlauf

Nützlich, um den IdP aus einem Skript oder einer Postman-Collection heraus anzutesten. Ersetzen Sie YOUR_CLIENT_ID, YOUR_REDIRECT_URI und die PKCE-Werte durch Ihre eigenen.

Schritt 1 — die Authorize-URL im Browser öffnen

https://phone.aloaha.com/oidc.ashx?action=authorize\ &response_type=code\ &client_id=YOUR_CLIENT_ID\ &redirect_uri=https%3A%2F%2Fyour-app.com%2Foidc%2Fcallback\ &scope=openid+profile+email\ &state=abc123\ &code_challenge=YOUR_S256_CHALLENGE\ &code_challenge_method=S256

Anmelden. Der Browser landet auf Ihrer Callback-URL mit ?code=<langer String>&state=abc123.

Schritt 2 — Code gegen Tokens tauschen

curl -X POST https://phone.aloaha.com/oidc.ashx?action=token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=<Code aus Schritt 1>" \ -d "redirect_uri=https://your-app.com/oidc/callback" \ -d "client_id=YOUR_CLIENT_ID" \ -d "code_verifier=YOUR_PKCE_VERIFIER"

Antwort:

{ "access_token": "eyJhbGc...", "token_type": "Bearer", "expires_in": 3600, "id_token": "eyJhbGc...", "refresh_token": "7m...", "scope": "openid profile email" }

Schritt 3 — Nutzerprofil abrufen

curl https://phone.aloaha.com/oidc.ashx?action=userinfo \ -H "Authorization: Bearer eyJhbGc..."

8. ID-Token validieren

Wenn Sie ID-Tokens serverseitig akzeptieren (zum Beispiel, um den Nutzer ohne Back-Channel-Call zu identifizieren), MÜSSEN Sie sie verifizieren. Validierung überspringen heißt: jeder kann Ihnen ein gefälschtes Token in die Hand drücken.

Jede OIDC/JOSE-Library erledigt das für Sie. Die nötigen Prüfungen:

  1. Signatur — gegen den öffentlichen Schlüssel aus jwks_uri verifizieren, passend zur kid im JWT-Header.
  2. iss — muss dem Issuer aus dem Discovery-Dokument entsprechen (https://www.aloaha.com).
  3. aud — muss Ihrer client_id entsprechen.
  4. exp — muss in der Zukunft liegen (ein paar Sekunden Clock-Skew zulassen).
  5. iat — Sanity-Check: nicht weit in der Zukunft.
  6. nonce — falls Sie eine an /authorize gesendet haben, muss sie im Token zurückkommen.

Decodierte ID-Token-Payload:

{ "iss": "https://www.aloaha.com", "sub": "alice", "aud": "YOUR_CLIENT_ID", "exp": 1748467200, "iat": 1748463600, "auth_time": 1748463600, "name": "Alice Walker", "preferred_username": "alice", "email": "alice@example.com", "email_verified": true, "role": "admin", "groups": ["admin"] }

Der role-Claim ist die CodeB-spezifische Rollen-Zuweisung (admin, user, siponly oder guest). Der Standard-groups-Claim ist per Default ein einelementiges Array mit der Rolle — das erwarten die meisten RPs. Admins können pro Nutzer überschreiben via Groups-Feld im Nutzerprofil-Editor (register.html) — wenn gesetzt, ersetzen diese Gruppen das Rolle-als-Gruppe-Default, was der empfohlene Weg ist, RP-spezifische Mitgliedschaften (Nextcloud-Gruppen, App-Rollen, Abteilungen) ins Token zu speisen.

9. Refresh + Logout

Access-Token erneuern

Access-Tokens laufen 1 Stunde. Refresh-Tokens 4 Stunden und werden bei jeder Nutzung rotiert (entsprechend OAuth-2.1-Best-Practice): jeder Aufruf von /token mit grant_type=refresh_token liefert ein frisches refresh_token, das alte wird sofort invalidiert. Speichern Sie das neue, werfen Sie das alte weg.

curl -X POST https://phone.aloaha.com/oidc.ashx?action=token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=refresh_token" \ -d "refresh_token=YOUR_REFRESH_TOKEN" \ -d "client_id=YOUR_CLIENT_ID"

Wenn Sie jemals ein bereits eingelöstes refresh_token vorlegen, antwortet der IdP mit invalid_grant. Das ist das Sicherheits-Feature der Rotation: es zeigt Ihnen, dass das Token anderswo benutzt wurde (mögliche Exfiltration). Erzwingen Sie eine erneute Anmeldung.

Nutzer abmelden

Löschen Sie Ihre eigene Session, dann optional auf den End-Session-Endpoint des IdP umleiten:

https://phone.aloaha.com/oidc.ashx?action=end_session\ &post_logout_redirect_uri=https%3A%2F%2Fyour-app.com%2Floggedout

Weil CodeB cookie-frei ist, ist der IdP-seitige Logout meist nur ein Redirect — es gibt kein IdP-Session-Cookie zu löschen. Die eigentliche Logout-Arbeit passiert bei Ihnen: Tokens wegwerfen.

10. Token-Widerruf (RFC 7009)

Sie müssen die Session eines Nutzers sofort IdP-seitig beenden (Admin-Aktion, Passwort-Änderung, Mitarbeiter-Abgang)? POSTen Sie das refresh_token an /oidc.ashx?action=revoke. Beim nächsten Refresh-Versuch des RP gibt es invalid_grant und der Nutzer muss sich erneut anmelden.

curl -X POST https://phone.aloaha.com/oidc.ashx?action=revoke \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "token=<das_refresh_token>" \ -d "token_type_hint=refresh_token" \ -d "client_id=YOUR_CLIENT_ID" \ -d "client_secret=YOUR_CLIENT_SECRET"

Liefert immer 200 {}, unabhängig davon, ob das Token existierte — das ist RFC 7009 §2.2 mit Absicht, um Token-Enumeration zu verhindern. Confidential Clients müssen client_secret mitschicken; Public Clients dürfen ohne Auth widerrufen.

Access-Tokens sind zustandslose JWTs mit 1h-TTL, deshalb macht RFC 7009 §2.2 serverseitigen Widerruf optional — CodeB macht Access-Token-Widerruf zum No-Op (liefert trotzdem 200). Um eine Session schneller zu beenden, widerrufen Sie das refresh_token UND lassen Sie den RP sein In-Memory-access_token verwerfen.

11. Authentifizierungs-Faktor (amr / acr)

Jedes ausgestellte id_token und access_token trägt zwei Claims, die beschreiben, wie sich der Nutzer tatsächlich authentifiziert hat:

RPs, die Step-up-Auth brauchen (z. B. Smartcard-Login für sensitive Operation erzwingen), können auf acr verzweigen:

if (idToken.acr !== 'urn:codeb:acr:hwk-mfa') { // Re-Auth mit stärkerem Faktor erzwingen: // /authorize?acr_values=urn:codeb:acr:hwk-mfa&... redirectToAuthorizeWithAcrValues(); }

Die Claims überleben Refresh-Token-Rotation, also bleibt der Faktor für die gesamte Session-Lebensdauer korrekt. Sie werden auch durch die cookielose SSO-Assertion getragen: meldet sich der Nutzer innerhalb des 30-min-Fensters bei einem zweiten RP an, sieht der neue RP denselben Faktor.

12. Key-Rotation-Runbook (Betreiber)

Der IdP signiert jedes JWT mit einem pro-Mandant 2048-Bit-RSA-Key. Für Rotation ohne Downtime unterstützt CodeB ein Überlappungsfenster: zwei Keys können gleichzeitig aktiv sein. Tokens, die vor der Rotation signiert wurden, verifizieren weiter via den vorigen Key, solange er auf der Platte liegt; neue Tokens werden mit dem frisch erzeugten Key signiert.

  1. SSH / RDP auf den IIS-Host.
  2. Aktuellen Key beiseite schieben:
    cd D:\aloaha\phone\App_Data\www.aloaha.com\oidc move private-key.xml private-key-previous.xml
  3. Der nächste Request an /oidc.ashx auf diesem Mandanten erkennt die fehlende private-key.xml und erzeugt eine frische. Der vorige Key bleibt als verify-only-Fallback geladen.
  4. JWKS publiziert nun beide öffentlichen Schlüssel (den neuen zuerst):
    curl https://www.aloaha.com/.well-known/jwks.json | jq .keys

    RPs, die JWKS regelmäßig holen, picken beide automatisch auf. Vor der Rotation signierte Tokens verifizieren weiter; neue Tokens verwenden die neue kid.

  5. Warten, bis das Überlappungsfenster leerläuft. Sobald jedes unter dem alten Key ausgegebene refresh_token rotiert wurde (max. 4 h bei Default-TTL), darf der vorige Key gelöscht werden:
    del D:\aloaha\phone\App_Data\www.aloaha.com\oidc\private-key-previous.xml

    JWKS fällt beim nächsten Request auf einen einzigen Key zurück; etwaige Nachzügler mit Token unter altem Key scheitern bei der Verifikation und müssen sich neu anmelden.

Der IdP mtime-überwacht beide Dateien, sodass die Rotation heiß ist — kein IIS-Recycle, keine abgebrochenen WebSocket-Sessions, keine kaputten laufenden Anmeldungen. Die kid in jedem JWT-Header pinnt es zur Verifikationszeit an den richtigen Key.

13. Fehlersuche

SymptomWahrscheinliche Ursache
invalid_client bei /authorize Ihre client_id ist nicht für diesen Mandanten registriert, oder Ihre redirect_uri entspricht nicht byte-genau dem registrierten Wert (Case, Trailing-Slash, Query-String).
invalid_request-Redirect Fehlende code_challenge oder code_challenge_method != S256. PKCE ist Pflicht.
invalid_grant: PKCE verifier invalid Der gesendete code_verifier ergibt nicht den vorher gesendeten code_challenge-SHA-256. Meist ein Tippfehler oder versehentlich den Challenge statt des Verifiers gesendet.
invalid_grant: code invalid or expired Auth-Codes sind single-use und leben 60 Sekunden. Nicht cachen; sofort beim Callback tauschen.
invalid_grant: refresh_token invalid Refresh-Tokens sind single-use (Rotation). Sie haben eines vorgelegt, das schon eingelöst war — entweder von Ihnen bei einem früheren Aufruf oder von einem Angreifer, falls es geleakt ist. Re-Login erzwingen.
401 invalid_token bei /userinfo Access-Token abgelaufen (1h) oder der falsche Mandanten-Key hat es signiert. Refresh + retry.
429 rate_limited bei /login Pro-IP-Rate-Limit (10 Fehlversuche pro Minute). Retry-After-Header beachten.
State-Mismatch beim Callback Ihr Frontend hat den gespeicherten state verloren (z. B. Nutzer hat die Auth-URL in einem anderen Tab geöffnet). Flow neu starten.

14. Schnellreferenz

WasWert
Discovery/.well-known/openid-configuration
JWKS/.well-known/jwks.json
Authorize/oidc.ashx?action=authorize
Token/oidc.ashx?action=token
UserInfo/oidc.ashx?action=userinfo
End-Session/oidc.ashx?action=end_session
Signatur-Alg.RS256 (2048-Bit RSA, pro-Mandant-Key)
PKCEfür alle Flows verpflichtend, nur S256
Grant-Typenauthorization_code, refresh_token
Access-Token-TTL3600s (1h)
ID-Token-TTL3600s (1h)
Refresh-Token-TTL14400s (4h), bei jeder Nutzung rotiert
Auth-Code-TTL60s, single-use
Scopesopenid, profile, email, groups, phone, address
Revocation-Endpoint/oidc.ashx?action=revoke
amr-Wertepwd, hwk, mfa, swk, otp
acr-Werteurn:codeb:acr:pwd, urn:codeb:acr:hwk, urn:codeb:acr:hwk-mfa, urn:codeb:acr:mfa
Key-RotationÜberlappungsfenster: private-key.xml → private-key-previous.xml umbenennen; neuer Key wird automatisch erzeugt; beide in JWKS publiziert
Rollen (im role-Claim)admin, user, siponly, guest

Hilfe beim Einbau gefällig? Schreiben Sie an info@aloaha.com · Zurück zur OIDC-Übersicht →

Siehe auch · Plattform-Integrations-Anleitungen

Häufige Fragen

Brauche ich PKCE?

Ja. PKCE ist für jeden Client (öffentlich und vertraulich) Pflicht, und zwar nur S256. Der IdP lehnt den authorization_code-Grant ohne code_verifier ab.

Wie registriere ich einen neuen Client?

Fügen Sie auf dem IdP-Host einen Eintrag mit client_id und redirect_uris in App_Data/<tenant>/oidc/clients.json hinzu. Die Datei wird im laufenden Betrieb neu geladen. Wenn Sie den Host nicht selbst betreiben, schreiben Sie an info@aloaha.com. Alle Clients sind reine PKCE-Public-Clients.

Warum erhalte ich invalid_client bei /authorize?

Entweder ist Ihre client_id für diesen Mandanten nicht registriert, oder Ihre redirect_uri stimmt nicht Byte für Byte mit dem registrierten Wert überein. Der IdP erzwingt eine exakte Übereinstimmung gemäß OIDC Core Abschnitt 3.1.2.1.

Warum hat /token bei einem PKCE-Verifier invalid_grant zurückgegeben?

Der gesendete code_verifier ergibt per SHA-256 nicht die zuvor gesendete code_challenge. Meist ist das ein Tippfehler oder es wurde versehentlich die Challenge statt des Verifiers gesendet.

Wie lange sind Tokens gültig?

Access Tokens: 1 Stunde. ID Tokens: 1 Stunde. Refresh Tokens: 4 Stunden, einmalig verwendbar (bei jeder Erneuerung rotiert). Authorization Codes: 60 Sekunden, einmalig verwendbar.

Warum funktioniert mein refresh_token plötzlich nicht mehr?

Refresh Tokens sind einmalig verwendbar. Wenn Sie eines vorlegen, das bereits eingelöst wurde (von Ihnen bei einem früheren Aufruf oder von einem Angreifer, falls es abgeflossen ist), gibt der IdP invalid_grant zurück. Lassen Sie den Benutzer sich erneut anmelden.

Wie rotiere ich den Signaturschlüssel des IdP ohne Ausfallzeit?

Benennen Sie App_Data/<tenant>/oidc/private-key.xml in private-key-previous.xml um. Die nächste Anfrage erzeugt eine neue private-key.xml; beide Schlüssel werden im JWKS veröffentlicht, bis Sie die vorherige Datei löschen. Vor der Rotation signierte Tokens lassen sich während des Überlappungszeitraums weiterhin verifizieren. Ein IIS-Recycle ist nicht nötig.

Wie beende ich die Sitzung eines Benutzers zwangsweise?

Senden Sie das Refresh Token per POST an /oidc.ashx?action=revoke mit token_type_hint=refresh_token. Gemäß RFC 7009 antwortet der Endpunkt immer mit 200, um Enumeration zu verhindern; der nächste Erneuerungsversuch scheitert mit invalid_grant und der Benutzer muss sich erneut authentifizieren.

Wie erkennt eine Relying Party, ob sich der Benutzer mit einem Hardware-Schlüssel angemeldet hat?

Lesen Sie die Claims amr und acr im id_token. amr=['hwk','mfa'] / acr='urn:codeb:acr:hwk-mfa' kennzeichnet MFA mit Hardware-Schlüssel; amr=['pwd'] / acr='urn:codeb:acr:pwd' ist die einfache HA1-Formularanmeldung. Beide Claims bleiben bei Refresh und SSO erhalten.

Setzt CodeB während des OIDC-Ablaufs Cookies?

Nein. Der CodeB-IdP arbeitet ohne Cookies. Das Anmeldeformular erzeugt den Auth-Code direkt und sendet ihn als JSON zurück; der Browser navigiert mit dem Code in der URL zu Ihrer redirect_uri. Zu keinem Zeitpunkt wird ein IdP-Sitzungscookie gesetzt.