Device Flow (RFC 8628)
Der OAuth 2.0 Device Authorization Grant (RFC 8628 ) ermöglicht es Geräten ohne eigenen Browser (CLI-Werkzeuge, Headless-Server, IoT-Geräte, Smart-TVs), einen Benutzer über einen zweiten Browser auf einem anderen Gerät zu authentifizieren.
Typische Anwendungsfälle:
- Login der ProcessCube CLI (
pc engine login) auf einem Build-Server oder über SSH - Headless-Tools, die Tokens für die Engine benötigen
- Geräte ohne Tastatur, bei denen eine
client_id+client_secretnicht sicher hinterlegt werden kann
Im Gegensatz zum Authorization Code Flow muss das Gerät keinen lokalen HTTP-Server für den Redirect betreiben. Im Gegensatz zum Client Credentials Flow wird ein konkreter Benutzer angemeldet — das Gerät bekommt Tokens im Namen dieses Benutzers, inklusive aller seiner Berechtigungen.
Ablauf
Voraussetzungen
- Eine laufende Authority ≥ v3.7.0
- Die
verification_urimuss vom Browser des Benutzers erreichbar sein - Ein Client mit
device_codein seinengrant_types— entweder der eingebautepc_cli-Client (siehe unten) oder ein eigener Client unterotherClients
Konfiguration
Die Authority bietet zwei Wege, den Device Flow nutzbar zu machen.
Variante 1: Eingebauter CLI-Client
Die Authority bringt einen vorbereiteten Client mit der client_id pc_cli mit, inklusive Device Flow
und Standard-Scopes für die Engine. Aktiviert wird er über das Konfigurationsfeld cli:
{
"issuerUrl": "http://authority:11560",
"applicationPort": 11560,
"cli": {
"enabled": true,
"additionalOidcClientSettings": {
"response_types": []
}
}
}Das Feld additionalOidcClientSettings.response_types: [] ist in v3.7.0 erforderlich. Ohne diesen
Override antwortet die Authority auf POST /device/auth mit dem Fehler
invalid_client_metadata: grant_types must contain 'authorization_code' when code is amongst response_types,
weil der Default response_types: ["code"] nicht zu den Device-Flow-Grants passt.
Damit ist client_id=pc_cli mit folgenden Voreinstellungen verfügbar:
| Eigenschaft | Wert |
|---|---|
client_id | pc_cli |
grant_types | urn:ietf:params:oauth:grant-type:device_code, refresh_token |
scope | openid profile engine_read engine_write engine_admin |
token_endpoint_auth_method | none (Public Client) |
Scope und Access-Token-Lebensdauer lassen sich überschreiben:
{
"cli": {
"enabled": true,
"scope": "openid profile engine_read",
"accessTokenTTL": 1800,
"additionalOidcClientSettings": {
"response_types": []
}
}
}Variante 2: Eigener Client via otherClients
Für Custom-CLIs, IoT-Geräte oder Drittanwendungen lässt sich ein eigener Client registrieren.
Wichtig ist der Eintrag device_code in grant_types — die Authority expandiert ihn automatisch
zur vollständigen RFC-URN urn:ietf:params:oauth:grant-type:device_code.
{
"otherClients": [
{
"clientId": "my-iot-device",
"scope": "openid profile engine_read",
"grant_types": ["device_code", "refresh_token"],
"redirect_uris": [],
"response_types": [],
"token_endpoint_auth_method": "none"
}
]
}response_types: [] ist für reine Device-Flow-Clients erforderlich, da der oidc-provider sonst implizit
["code"] annimmt und beim Aufruf von POST /device/auth einen Validierungsfehler wirft.
Public Clients (Geräte ohne sicheren Speicher für ein Secret) setzen token_endpoint_auth_method: "none"
und liefern beim Token-Abruf kein client_secret mit.
Empfohlene Scopes
| Use-Case | Scope |
|---|---|
| Lesender Engine-Zugriff (z.B. Monitoring-Tool) | openid profile engine_read |
| CLI mit Deploy-Rechten | openid profile engine_read engine_write |
| Administrative CLI | openid profile engine_read engine_write engine_admin |
Verwendung Schritt für Schritt
Gerät startet den Flow
Das Gerät fragt einen device_code und einen user_code beim Device-Authorization-Endpunkt an.
Die genaue URL liefert das OIDC-Discovery-Dokument unter /.well-known/openid-configuration im Feld
device_authorization_endpoint — bei der ProcessCube Authority ist das /device/auth.
curl -X POST http://localhost:11560/device/auth \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=pc_cli" \
-d "scope=openid profile engine_read"Antwort (gekürzt):
{
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
"user_code": "ABCD-EFGH",
"verification_uri": "http://localhost:11560/device",
"verification_uri_complete": "http://localhost:11560/device?user_code=ABCD-EFGH",
"expires_in": 600
}| Feld | Bedeutung |
|---|---|
device_code | Identifiziert den Flow gegenüber der Authority. Niemals anzeigen. |
user_code | Kurzer Code, den der Benutzer im Browser eingibt. |
verification_uri | URL, die der Benutzer öffnet. |
verification_uri_complete | URL mit vorausgefülltem Code (für QR-Codes oder open()-Aufrufe). |
expires_in | Gültigkeit des device_code in Sekunden. |
interval | Mindest-Polling-Intervall in Sekunden. Optional — fehlt der Wert, sind 5 Sekunden ein sinnvoller Default. |
Gerät zeigt den Code an
Das Gerät zeigt dem Benutzer verification_uri und user_code an. Hat das Gerät ein Display, kann auch ein
QR-Code mit verification_uri_complete angezeigt werden.
Benutzer öffnet die Verification-URI
Der Benutzer öffnet die verification_uri in einem Browser auf einem beliebigen Gerät (Laptop, Smartphone).
Die Authority zeigt eine Eingabemaske für den user_code:

Geräte-Bestätigung
Nach Eingabe des Codes zeigt die Authority eine Zwischenseite „Authorize Device” an, auf der Client und
anfragende IP-Adresse sichtbar sind. Hier kann der Benutzer den Vorgang noch abbrechen (Deny), bevor er
sich anmeldet. Mit Authorize geht es weiter zum Login.
Benutzer meldet sich an
Falls noch keine Session existiert, durchläuft der Benutzer den normalen Login-Flow (siehe Username & Password Extension oder Externe Identitätsprovider).
Benutzer bestätigt die Scopes
Nach dem Login zeigt die Authority an, welche Berechtigungen (Scopes & Claims) angefragt werden.
Der Benutzer bestätigt mit OK:

Erfolgsseite
Nach Zustimmung erscheint eine Erfolgsmeldung. Der Browser kann geschlossen werden:

Gerät pollt den Token-Endpunkt
Parallel zum Browser-Login pollt das Gerät den Token-Endpunkt mit dem device_code. Vor der Bestätigung
antwortet die Authority mit authorization_pending. Sobald der Benutzer zugestimmt hat, liefert sie
access_token, id_token und refresh_token:
curl -X POST http://localhost:11560/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
-d "device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS" \
-d "client_id=pc_cli"Erfolgsantwort:
{
"access_token": "eyJhbGciOi...",
"id_token": "eyJhbGciOi...",
"refresh_token": "...",
"token_type": "Bearer",
"expires_in": 3600
}Beispiele
Bash (curl)
Vollständiger Bash-Lauf mit curl und jq:
#!/usr/bin/env bash
set -euo pipefail
AUTHORITY="${AUTHORITY:-http://localhost:11560}"
CLIENT_ID="${CLIENT_ID:-pc_cli}"
SCOPE="${SCOPE:-openid profile engine_read}"
# 1. Device Authorization Request
resp=$(curl -sS -X POST "$AUTHORITY/device/auth" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode "scope=$SCOPE")
device_code=$(echo "$resp" | jq -r .device_code)
user_code=$(echo "$resp" | jq -r .user_code)
verification_uri=$(echo "$resp" | jq -r .verification_uri)
interval=$(echo "$resp" | jq -r '.interval // 5')
echo "Open: $verification_uri"
echo "Code: $user_code"
# 2. Polling
while true; do
sleep "$interval"
token_resp=$(curl -sS -X POST "$AUTHORITY/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
--data-urlencode "device_code=$device_code" \
--data-urlencode "client_id=$CLIENT_ID")
error=$(echo "$token_resp" | jq -r '.error // empty')
case "$error" in
"") echo "$token_resp" | jq .; exit 0 ;;
authorization_pending) continue ;;
slow_down) interval=$((interval + 5)); continue ;;
*) echo "Error: $error" >&2; exit 1 ;;
esac
doneFehlerbehandlung
Beim Polling kann der Token-Endpunkt folgende Fehler liefern (OAuth 2.0 Standard):
| Fehler | Bedeutung | Reaktion des Geräts |
|---|---|---|
authorization_pending | Benutzer hat noch nicht zugestimmt. | Weiter pollen im aktuellen Intervall. |
slow_down | Polling ist zu häufig. | Intervall um mindestens 5 Sekunden erhöhen, dann weiter pollen. |
expired_token | device_code ist abgelaufen (expires_in erreicht). | Polling abbrechen, neuen Flow starten. |
access_denied | Benutzer hat abgelehnt. | Polling abbrechen, Fehlermeldung anzeigen. |
invalid_grant | device_code ist ungültig oder bereits verwendet. | Polling abbrechen, neuen Flow starten. |
invalid_client | Client unbekannt oder device_code-Grant nicht freigeschaltet. | Konfiguration prüfen. |
Sicherheitshinweise
Device Flow wird typischerweise mit Public Clients (token_endpoint_auth_method: "none") verwendet —
ohne client_secret. Beachte daher:
- TLS verpflichtend im Produktivbetrieb. Der
device_codedarf niemals unverschlüsselt übertragen werden. - Kurze Lebensdauer für
device_code(Default: 10 Minuten). Nutzer müssen den Flow zeitnah abschließen. - Scope-Bestätigung vor der Tokenausgabe ist Pflicht. Der Benutzer sieht, welches Gerät welche Berechtigungen erhält.
- Phishing-Resistenz: Benutzer sollten die
verification_uriimmer manuell prüfen — Angreifer könnten versuchen, eigeneuser_codes über eine andere URL abzufangen.
Weiterführend
pc engine login— CLI-Befehl mit Device-Flow-Optionen- Konfiguration — vollständige Authority-Konfiguration
- REST-API — alle Authority-Endpunkte
- RFC 8628 — OAuth 2.0 Device Authorization Grant