Skip to Content
AuthorityDevice Flow (RFC 8628)

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_secret nicht 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_uri muss vom Browser des Benutzers erreichbar sein
  • Ein Client mit device_code in seinen grant_types — entweder der eingebaute pc_cli-Client (siehe unten) oder ein eigener Client unter otherClients

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:

.processcube/authority/config.json
{ "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:

EigenschaftWert
client_idpc_cli
grant_typesurn:ietf:params:oauth:grant-type:device_code, refresh_token
scopeopenid profile engine_read engine_write engine_admin
token_endpoint_auth_methodnone (Public Client)

Scope und Access-Token-Lebensdauer lassen sich überschreiben:

.processcube/authority/config.json
{ "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.

.processcube/authority/config.json
{ "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-CaseScope
Lesender Engine-Zugriff (z.B. Monitoring-Tool)openid profile engine_read
CLI mit Deploy-Rechtenopenid profile engine_read engine_write
Administrative CLIopenid 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 }
FeldBedeutung
device_codeIdentifiziert den Flow gegenüber der Authority. Niemals anzeigen.
user_codeKurzer Code, den der Benutzer im Browser eingibt.
verification_uriURL, die der Benutzer öffnet.
verification_uri_completeURL mit vorausgefülltem Code (für QR-Codes oder open()-Aufrufe).
expires_inGültigkeit des device_code in Sekunden.
intervalMindest-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:

Eingabe des User-Codes

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:

Bestaetigung der Scopes

Erfolgsseite

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

Erfolgsseite

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

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 done

Fehlerbehandlung

Beim Polling kann der Token-Endpunkt folgende Fehler liefern (OAuth 2.0 Standard):

FehlerBedeutungReaktion des Geräts
authorization_pendingBenutzer hat noch nicht zugestimmt.Weiter pollen im aktuellen Intervall.
slow_downPolling ist zu häufig.Intervall um mindestens 5 Sekunden erhöhen, dann weiter pollen.
expired_tokendevice_code ist abgelaufen (expires_in erreicht).Polling abbrechen, neuen Flow starten.
access_deniedBenutzer hat abgelehnt.Polling abbrechen, Fehlermeldung anzeigen.
invalid_grantdevice_code ist ungültig oder bereits verwendet.Polling abbrechen, neuen Flow starten.
invalid_clientClient 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_code darf 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_uri immer manuell prüfen — Angreifer könnten versuchen, eigene user_codes über eine andere URL abzufangen.

Weiterführend