Claim-Flow (service_auth & anonym)
Wie ein Agent aus einer Registrierung ein nur lesendes, kontogebundenes Zugriffstoken macht, indem ein angemeldeter Nutzer ihn autorisiert.
Claim-Flow
Ein Claim bindet die Registrierung eines Agenten an die Organisation eines angemeldeten
Nutzers (oder an einen einzelnen Kunden darin) und gewährt ein nur lesendes (api.read)
Zugriffstoken. Agenten erhalten dabei nie Schreibzugriff. Es gibt zwei Wege zu einem Claim:
service_authstartet die Claim-Zeremonie sofort und liefert denuser_codedirekt an den aufrufenden Agenten zurück (eine vertrauenswürdige Integration im Device-Flow-Stil).- Eine
anonymous-Registrierung (siehe Agent-Authentifizierung) ist sofort nutzbar und kann optional später perPOST /agent/identity/claimhochgestuft werden: deruser_codewird dem Agenten auf diesem Weg nie zurückgegeben; nur der angemeldete Nutzer sieht ihn.
1. Mit service_auth registrieren
POST https://uptimeify.io/agent/identity
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
type | string | ja | "service_auth" |
login_hint | string | ja | E-Mail des Nutzers, der den Agenten autorisieren wird. Muss ein @ enthalten. |
curl -X POST https://uptimeify.io/agent/identity \
-H 'Content-Type: application/json' \
-d '{"type":"service_auth","login_hint":"user@deinkunde.com"}'{
"registration_id": "reg_…",
"claim": {
"user_code": "WDJB-MJHT",
"verification_uri": "https://uptimeify.io/claim",
"expires_in": 600,
"interval": 5
},
"claim_token": "clm_…",
"post_claim_scopes": ["api.read"]
}Zeige verification_uri und user_code deinem Nutzer an (ein Prompt im Stil des
RFC-8628-Device-Flows). Die Registrierung startet mit status: pending und erzeugt kein
Zugriffstoken, bis die Zeremonie abgeschlossen ist. Poll dazu mit dem claim_token in
Schritt 3 unten.
user_code und claim_token laufen beide nach expires_in Sekunden ab (600s / 10 Minuten);
rufe erneut POST /agent/identity auf, um eine neue Zeremonie zu starten, falls die Zeit
abläuft.
2. Oder: eine bestehende anonymous-Registrierung claimen
POST https://uptimeify.io/agent/identity/claim
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
claim_token | string | ja | Das clm_… aus einem früheren Aufruf von POST /agent/identity {"type":"anonymous"}. |
email | string | ja | E-Mail des Nutzers, der den Claim autorisieren wird. Muss ein @ enthalten. |
curl -X POST https://uptimeify.io/agent/identity/claim \
-H 'Content-Type: application/json' \
-d '{"claim_token":"clm_…","email":"user@deinkunde.com"}'{
"verification_uri": "https://uptimeify.io/claim?claim_attempt=cat_…",
"claim_attempt_token": "cat_…",
"expires_in": 600,
"interval": 5
}Beachte, was fehlt: user_code. Auf diesem Weg erfährt der Agent den Code nie, nur der
angemeldete, an die E-Mail gebundene Nutzer sieht ihn, auf der /claim-Seite. Die
Registrierung selbst bleibt während der ganzen Zeremonie active und funktioniert
durchgehend mit ihrem tools.public-Scope weiter: das Claimen fügt nur api.read hinzu, es
entzieht dem anonymen Zugriff während des laufenden Vorgangs nichts. Ein erneuter Aufruf
dieses Endpunkts vor Ablauf überschreibt Code/Attempt-Token und setzt das 10-Minuten-Fenster
zurück.
Eine Registrierung kann nur einmal geclaimt werden: Ein zweiter Aufruf von
POST /agent/identity/claim (oder ein service_auth-Claim, der immer schon vorab gebunden
ist) nach erfolgter Bestätigung liefert 409 claimed_or_in_flight.
3. Menschliche Zustimmung unter /claim
Der gebundene Nutzer muss unter genau dem oben verwendeten login_hint/email bei Uptimeify
angemeldet sein und entweder den vom Agenten angezeigten user_code eintippen oder den
verification_uri-Link öffnen (der beim anonymen Weg ?claim_attempt=… trägt). Die
Uptimeify-Web-App löst das über zwei sitzungscookie-authentifizierte Endpunkte zum
Bestätigungsbildschirm auf: diese ruft der Agent nicht selbst auf, sie sind hier nur der
Vollständigkeit halber dokumentiert:
GET /api/agent-claim/context?claim_attempt=<token>: liefert für den angemeldeten, gebundenen Nutzer{ registration_id, agent_type, scope, bound_email, user_code, expires_at }, damit die UI zeigen kann, was autorisiert wird (und beim anonymen Weg den Code vorausfüllen kann).POST /api/agent-claim/confirm { user_code }: der angemeldete Nutzer sendet den Code zur Autorisierung. Bei Erfolg:{ ok: true, registration_id }.
Die Bestätigung bindet die Registrierung an die Organisation des Nutzers, oder, wenn dessen
Rolle ihn auf genau einen Kunden beschränkt, an diesen einen Kunden. Ein admin oder ein
uneingeschränkter editor bindet die gesamte Organisation; ein readonly- (oder
editor-)Nutzer, der auf genau einen Kunden beschränkt ist, bindet diesen Kunden; jeder
andere Fall (kein als einzelner Scope darstellbarer Kunde, z. B. eine Rolle responder, oder
ein readonly-Nutzer mit mehreren zugewiesenen Kunden) lässt die Bestätigung fehlschlagen:
der Agent sieht dann expired_token/invalid_claim_token, statt jemals ein zu breites oder
mehrdeutiges Token zu erhalten.
4. Auf Abschluss pollen
POST https://uptimeify.io/oauth2/token (application/x-www-form-urlencoded)
| Feld | Erforderlich | Beschreibung |
|---|---|---|
grant_type | ja | urn:uptimeify:agent-auth:grant-type:claim |
claim_token | ja | Das clm_… aus Schritt 1 (bzw. die ursprüngliche anonyme Registrierung aus Schritt 2). |
curl -X POST https://uptimeify.io/oauth2/token \
--data-urlencode 'grant_type=urn:uptimeify:agent-auth:grant-type:claim' \
--data-urlencode 'claim_token=clm_…'Poll nicht schneller als das interval aus Schritt 1/2 (5 Sekunden). Jeder Poll liefert
eines von:
| Status | HTTP | error | Bedeutung |
|---|---|---|---|
| Noch nicht bestätigt | 400 | authorization_pending | Weiter im interval pollen. |
| Zu schnell gepollt | 400 | slow_down | Drossle dich: du hast schneller als interval gepollt. |
| Token/Registrierung weg | 400 | expired_token | Der Claim-Token ist unbekannt, seine Registrierung wurde widerrufen/ist abgelaufen, das äußere 24h-Fenster ist verstrichen, oder er wurde bereits durch einen früheren Poll eingelöst. |
| Bestätigt | 200 | - | Erfolg: siehe unten. |
Bei Erfolg:
{
"access_token": "wsma_…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "api.read",
"identity_assertion": "eyJ…"
}Der claim_token ist einmal verwendbar: Er wird beim ersten erfolgreichen Poll atomar
verbraucht, sodass niemals zwei gleichzeitige/wiederholte Poller beide ein Token erzeugen
können. Das Einlösen widerruft in derselben Alles-oder-nichts-Operation auch alle vorherigen
tools.public-Zugriffstokens derselben Registrierung: die Vorab-Tokens einer anonymen
Registrierung funktionieren nach dem Claim nicht mehr.
Speichere die zurückgegebene identity_assertion (ein EdDSA-JWT mit rund 24 Stunden
Gültigkeit, wie im Basis-Flow) und tausche sie erneut über den Grant
urn:ietf:params:oauth:grant-type:jwt-bearer (siehe
Agent-Authentifizierung), um nach
Ablauf frische api.read-Zugriffstokens zu erzeugen. Die Claim-Zeremonie musst du dafür
nicht wiederholen.
5. Das Token verwenden (nur lesend)
Das wsma_-Zugriffstoken aus einem abgeschlossenen Claim ist nur lesend und auf die
Organisation (bzw. den einzelnen Kunden) des autorisierenden Nutzers begrenzt:
GET /api/websites*, GET /api/incidents* und GET /api/health. Jeder Schreibzugriff oder
jede Anfrage außerhalb dieser Allowlist liefert 403 mit data.code = agentTokenReadOnly.
Noch nicht verfügbar
identity_assertion als Registrierungs-type (ID-JAG, womit eine bereits vertraute externe
OIDC-Identität ohne jede Claim-Zeremonie direkt ein Token erzeugen könnte) ist noch nicht
aktiviert. Verlasse dich nicht darauf; POST /agent/identity {"type":"identity_assertion"}
liefert derzeit 400 issuer_not_enabled.
Häufige Fehler
| HTTP | error / data.code | Wo | Bedeutung |
|---|---|---|---|
| 400 | service_auth_not_enabled | POST /agent/identity | service_auth ist auf diesem Deployment nicht aktiviert. |
| 400 | invalid_request | POST /agent/identity, POST /agent/identity/claim, /api/agent-claim/* | Fehlendes/ungültiges login_hint, claim_token, email oder user_code. |
| 400 | invalid_claim_token | POST /agent/identity/claim | Unbekannter Claim-Token, oder die Registrierung des Tokens ist nicht anonymous, oder sie wurde widerrufen. |
| 404 | invalid_claim_token | GET /api/agent-claim/context | Der claim_attempt-Token ist unbekannt/abgelaufen, oder der angemeldete Nutzer ist nicht die gebundene E-Mail, beides ununterscheidbar (fail-closed). |
| 400 | invalid_claim_token | POST /api/agent-claim/confirm | Der user_code ist falsch/abgelaufen, oder der Zugriff des bestätigenden Nutzers lässt sich nicht auf einen einzelnen Org-/Kunden-Scope auflösen. |
| 409 | claimed_or_in_flight | POST /agent/identity/claim | Die Registrierung ist bereits geclaimt (organizationId ist schon gesetzt). |
| 400 | claim_expired | POST /agent/identity/claim | Das äußere 24h-Claim-Fenster (ab Erstellung der Registrierung) ist verstrichen. |
| 400 | authorization_pending | POST /oauth2/token (Claim-Grant) | Der Nutzer hat noch nicht bestätigt: weiter pollen. |
| 400 | slow_down | POST /oauth2/token (Claim-Grant) | Schneller als interval (5s) gepollt, drossle dich. |
| 400 | expired_token | POST /oauth2/token (Claim-Grant) | Der Claim-Token/die Registrierung ist abgelaufen, wurde widerrufen oder bereits eingelöst. |
| 403 | agentTokenReadOnly | Jeder /api/*-Aufruf mit wsma_-Token | Schreibversuch, oder ein Pfad außerhalb der nur-lesenden Allowlist des Tokens. |
| 429 | - | Jeder Endpunkt oben | Rate-Limit überschritten (siehe Agent-Authentifizierung). |
Die vollständige, kanonische Liste findest du in der Fehlercode-Referenz.