Schnellstart: jede OIDC-Bibliothek
Usher ist ein standardkonformer OpenID-Connect-Provider. Gibt es für deine Sprache einen zertifizierten OIDC-Client, hast du schon alles, was du brauchst: Richte ihn auf das Discovery-Dokument deiner Umgebung aus und verwende den Autorisierungscode-Flow mit PKCE.
Die Einstellungen
| Einstellung | Wert |
|---|---|
| Issuer | https://<handle>.usherid.com |
| Discovery-URL | https://<handle>.usherid.com/.well-known/openid-configuration |
| Flow | Autorisierungscode (response_type=code) |
| PKCE | Pflicht, code_challenge_method=S256 |
| Scopes | openid profile email offline_access |
| Client-Authentifizierung | Wie in token_endpoint_auth_methods_supported aufgeführt |
Das Handle deiner Umgebung findest du in Usher Console, neben ihrem Issuer. Entwicklungsumgebungen bekommen ein zufälliges, etwa wise-otter-42; Produktionsumgebungen haben das Handle, das du gewählt hast. Eine Produktionsumgebung kann stattdessen auch unter deiner eigenen Domain liegen, etwa login.acme.com: Das ist dann ihr Issuer, sobald du die Domain mit einem CNAME-Eintrag auf Usher verweisen lässt.
Lies das Discovery-Dokument
Hier steht jeder Endpunkt und jeder Schlüssel, den dein Client braucht. Lass deine Bibliothek das Dokument lesen, statt URLs in deinen Code zu kopieren.
curl -s https://acme.usherid.com/.well-known/openid-configuration | jq{
"issuer": "https://acme.usherid.com",
"authorization_endpoint": "https://acme.usherid.com/api/auth/oauth2/authorize",
"token_endpoint": "https://acme.usherid.com/api/auth/oauth2/token",
"userinfo_endpoint": "https://acme.usherid.com/api/auth/oauth2/userinfo",
"jwks_uri": "https://acme.usherid.com/api/auth/jwks",
"introspection_endpoint": "https://acme.usherid.com/api/auth/oauth2/introspect",
"revocation_endpoint": "https://acme.usherid.com/api/auth/oauth2/revoke",
"end_session_endpoint": "https://acme.usherid.com/api/auth/oauth2/end-session",
"scopes_supported": ["openid", "profile", "email", "offline_access"],
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token", "client_credentials"],
"code_challenge_methods_supported": ["S256"]
}Der Flow
Schick die Person zum Autorisierungsendpunkt
Erzeuge einen zufälligen PKCE-Verifier und bewahre ihn zusammen mit einem zufälligen state dort auf, wo nur die Sitzung dieses Browsers herankommt (ein kurzlebiges httpOnly-Cookie eignet sich gut). Leite dann weiter, mit response_type=code, deiner client_id und redirect_uri, den Scopes oben, dem state und der S256-code_challenge deines Verifiers.
Lass sie sich anmelden
Ab hier übernimmt die Lobby: Sie nennt deine App, bietet die Anmeldemethoden an, die deine Umgebung erlaubt, und fragt beim ersten Mal nach der Einwilligung.
Prüfe den Callback
Usher leitet mit code und state an deine redirect_uri weiter. Lehne die Antwort ab, wenn state nicht mit dem gespeicherten Wert übereinstimmt. Der Code ist nur einmal verwendbar und gilt fünf Minuten.
Tausche den Code gegen Tokens
Sende den Code und den PKCE-Verifier von deinem Server aus per POST an den Token-Endpunkt:
curl -s -X POST https://acme.usherid.com/api/auth/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code="$CODE" \
-d redirect_uri=https://app.acme.example/callback \
-d code_verifier="$CODE_VERIFIER"Prüfe das ID-Token
Prüfe seine Signatur mit den Schlüsseln unter jwks_uri und stelle sicher, dass iss dein Issuer ist, aud deine Client-ID und exp in der Zukunft liegt. Deine Bibliothek erledigt das für dich; achte nur darauf, dass diese Prüfung nicht abgeschaltet ist.
In Node.js
openid-client erledigt alles oben Beschriebene, einschließlich der Prüfung:
import * as client from 'openid-client'
// discovery: every endpoint and key comes from the issuer
const config = await client.discovery(
new URL('https://acme.usherid.com'),
process.env.USHER_CLIENT_ID!,
process.env.USHER_CLIENT_SECRET!,
)
// 1. send them to the Lobby, with PKCE (S256) and a state to check later
const codeVerifier = client.randomPKCECodeVerifier()
const state = client.randomState()
const url = client.buildAuthorizationUrl(config, {
redirect_uri: 'https://app.acme.example/callback',
scope: 'openid profile email offline_access',
code_challenge: await client.calculatePKCECodeChallenge(codeVerifier),
code_challenge_method: 'S256',
state,
})
// keep codeVerifier and state in a short-lived httpOnly cookie, then redirect to url
// 2. back at /callback: swap the code for tokens
const tokens = await client.authorizationCodeGrant(config, new URL(request.url), {
pkceCodeVerifier: codeVerifier,
expectedState: state,
})
const { sub, email, name } = tokens.claims()!In anderen Sprachen
Diese verbreiteten Bibliotheken sprechen alle standardkonformes OpenID Connect und funktionieren mit Usher ohne jede Usher-spezifische Anpassung:
| Sprache | Bibliothek |
|---|---|
| Python | Authlib |
| Go | coreos/go-oidc mit golang.org/x/oauth2 |
| Java | Spring Security OAuth 2.0 Client |
| .NET | Microsoft.AspNetCore.Authentication.OpenIdConnect |
| Ruby | omniauth_openid_connect |
| PHP | jumbojett/openid-connect-php |
Angemeldet bleiben
Mit dem Scope offline_access enthält die Token-Antwort ein Refresh-Token. Verwende es mit grant_type=refresh_token, um ein neues Access-Token zu holen, wenn das alte abläuft. Refresh-Tokens werden rotiert: Jede Verwendung liefert ein neues, und das alte funktioniert nicht mehr.
Abmelden
Beende zuerst deine eigene Sitzung und leite dann zum end_session_endpoint weiter, mit post_logout_redirect_uri (und id_token_hint, falls vorhanden), damit auch die Lobby die Person vergisst.