Authentifizierung
OAuth-Apps
Für Apps, die im Namen anderer Gravl-Nutzer handeln. Standard-OAuth-2.0-Authorization-Code mit PKCE: Nutzer gewähren deiner App bestimmte Scopes, du bekommst kurzlebige Access Tokens mit einem rotierenden Refresh Token, und der Grant ist jederzeit widerrufbar.
1. App registrieren
Solange die API in der Beta ist, läuft die Registrierung manuell. Schreib an developers@gravl.ai mit:
- Dem Namen deiner App und einer kurzen Beschreibung, was sie tut
- Deiner/deinen OAuth Redirect URI(s): absolute
https-URLs (http://localhostist für die Entwicklung erlaubt) - Den Scopes, die deine App braucht. Fordere das Minimum an; Nutzer sehen genau, was du anfragst
Du erhältst eine client_id (gci_…) und ein client_secret (gcs_…, wird nur einmal angezeigt; behandle es wie ein Passwort).
2. Nutzer zum Consent-Screen schicken
https://api.gravl.ai/oauth/authorize
?client_id=gci_…
&redirect_uri=https://yourapp.example/callback // must be registered exactly
&scope=workouts:read stats:read // omit for all allowed scopes
&state=<random value you verify on return>
&code_challenge=<S256(code_verifier)>
&code_challenge_method=S256Der Nutzer meldet sich mit seinem Gravl-Account an, sieht den Namen deiner App und die angefragten Scopes in verständlicher Sprache und stimmt zu. Sein Browser kommt zu deiner redirect_uri zurück, mit ?code=gac_…&state=… (oder error=access_denied, wenn er abbricht).
- Codes haben das Präfix
gac_, sind 10 Minuten gültig, einmalig verwendbar und an deine App sowie dieredirect_urigebunden, für die sie ausgestellt wurden - PKCE (S256) ist für Public Clients erforderlich (Browser- oder native Apps, die kein
client_secrethaben) und für alle anderen dringend empfohlen - Prüfe immer, ob
statemit dem übereinstimmt, was du gesendet hast; das ist dein CSRF-Schutz
Public Clients lassen client_secret am Token-Endpoint weg; PKCE ist ihre Client-Authentifizierung. Sag uns bei der Registrierung, welcher Typ deine App ist.
3. Code einlösen
curl -X POST https://api.gravl.ai/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d grant_type=authorization_code \
-d code=gac_… \
-d client_id=gci_… \
-d client_secret=gcs_… \
-d code_verifier=<your PKCE verifier> \
-d redirect_uri=https://yourapp.example/callback
{
"access_token": "gat_…",
"token_type": "Bearer",
"expires_in": 21600,
"refresh_token": "grt_…",
"scope": "workouts:read stats:read"
}| Token | Lebensdauer | Hinweise |
|---|---|---|
access_token | 6 Stunden | Bearer Token für /api/v1-Requests. |
refresh_token | Bis zu 180 Tage | Einmalig verwendbar; jeder Refresh widerruft es und stellt ein neues Paar aus (Rotation). |
4. Refresh
curl -X POST https://api.gravl.ai/oauth/token \
-d grant_type=refresh_token \
-d refresh_token=grt_… \
-d client_id=gci_… \
-d client_secret=gcs_…Die Response hat dieselbe Form wie beim Code-Austausch. Das vorgelegte Refresh Token wird in derselben Transaktion widerrufen; speichere also immer erst das neue refresh_token, bevor du das alte verwirfst. Das erneute Einreichen eines bereits benutzten Refresh Tokens gibt invalid_grant zurück.
5. Widerrufen
curl -X POST https://api.gravl.ai/oauth/revoke \
-d token=grt_… \
-d client_id=gci_… \
-d client_secret=gcs_…- Der Widerruf eines Access Tokens beendet nur dieses Token
- Der Widerruf eines Refresh Tokens widerruft den gesamten Grant: jedes ausstehende Token für dieses Nutzer-App-Paar
- Gemäß RFC 7009 gibt der Endpoint auch bei unbekannten Tokens
200zurück; nur falsche Client-Credentials erzeugen einen Fehler - Nutzer können den Zugriff deiner App auch aus ihrem Account heraus widerrufen
Fehler am Token-Endpoint
Fehler folgen RFC 6749: { "error": "…", "error_description": "…" }:
| Fehler | Status | Bedeutung |
|---|---|---|
invalid_request | 400 | Ein erforderlicher Parameter fehlt (z. B. code, refresh_token). |
invalid_client | 401 | Unbekannte client_id, falsches client_secret, oder die App ist gesperrt. |
invalid_grant | 400 | Code/Refresh Token ist abgelaufen, widerrufen, bereits benutzt, gehört zu einer anderen App, oder die PKCE-/redirect_uri-Prüfung schlug fehl. |
unsupported_grant_type | 400 | grant_type muss authorization_code oder refresh_token sein. |