Zum Inhalt springen
Dokumentation · Jede OIDC-Bibliothek

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

EinstellungWert
Issuerhttps://<handle>.usherid.com
Discovery-URLhttps://<handle>.usherid.com/.well-known/openid-configuration
FlowAutorisierungscode (response_type=code)
PKCEPflicht, code_challenge_method=S256
Scopesopenid profile email offline_access
Client-AuthentifizierungWie 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.

Terminal
curl -s https://acme.usherid.com/.well-known/openid-configuration | jq
Antwort (gekürzt)
{
  "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:

Token-Anfrage
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:

openid-client
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:

SpracheBibliothek
PythonAuthlib
Gocoreos/go-oidc mit golang.org/x/oauth2
JavaSpring Security OAuth 2.0 Client
.NETMicrosoft.AspNetCore.Authentication.OpenIdConnect
Rubyomniauth_openid_connect
PHPjumbojett/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.