Authentification
Apps OAuth
Pour les apps qui agissent au nom d’autres utilisateurs Gravl. OAuth 2.0 authorization-code standard avec PKCE : les utilisateurs accordent à ton app des scopes précis, tu obtiens des access tokens de courte durée avec un refresh token rotatif, et l’autorisation est révocable à tout moment.
1. Enregistre ton app
L’enregistrement est manuel tant que l’API est en bêta. Écris à developers@gravl.ai avec :
- Le nom de ton app et une courte description de ce qu’elle fait
- Ta ou tes redirect URI OAuth : des URLs
httpsabsolues (http://localhostautorisé pour le développement) - Les scopes dont ton app a besoin : demande le minimum ; les utilisateurs voient exactement ce que tu demandes
Tu recevras un client_id (gci_…) et un client_secret (gcs_…, affiché une seule fois : stocke-le comme un mot de passe).
2. Envoie l’utilisateur vers l’écran de consentement
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=S256L’utilisateur se connecte avec son compte Gravl, voit le nom de ton app et les scopes demandés en langage clair, puis approuve : son navigateur revient sur ta redirect_uri avec ?code=gac_…&state=… (ou error=access_denied s’il annule).
- Les codes sont préfixés
gac_, valables 10 minutes, à usage unique, et liés à ton app et à laredirect_uripour laquelle ils ont été émis - PKCE (S256) est requis pour les clients publics (apps navigateur ou natives, qui n’ont pas de
client_secret) et fortement recommandé pour tout le monde - Vérifie toujours que
statecorrespond à ce que tu as envoyé : c’est ta protection CSRF
Les clients publics omettent client_secret sur l’endpoint de token : PKCE fait office d’authentification client. Dis-nous de quel type est ton app au moment de l’enregistrement.
3. Échange le code
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 | Durée de vie | Notes |
|---|---|---|
access_token | 6 heures | Token Bearer pour les requêtes /api/v1. |
refresh_token | Jusqu’à 180 jours | Usage unique : chaque refresh le révoque et émet une nouvelle paire (rotation). |
4. Rafraîchir
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_…La réponse a la même forme que l’échange de code. Le refresh token présenté est révoqué dans la même transaction : persiste toujours le nouveau refresh_token avant de jeter l’ancien. Rejouer un refresh token déjà utilisé renvoie invalid_grant.
5. Révoquer
curl -X POST https://api.gravl.ai/oauth/revoke \
-d token=grt_… \
-d client_id=gci_… \
-d client_secret=gcs_…- Révoquer un access token ne tue que ce token
- Révoquer un refresh token révoque l’autorisation entière : tous les tokens en circulation pour ce couple utilisateur + app
- Conformément à la RFC 7009, l’endpoint renvoie
200même pour un token inconnu : seuls de mauvais identifiants client produisent une erreur - Les utilisateurs peuvent aussi révoquer l’accès de ton app depuis leur compte
Erreurs de l’endpoint de token
Les erreurs suivent la RFC 6749, au format { "error": "…", "error_description": "…" }:
| Erreur | Statut | Signification |
|---|---|---|
invalid_request | 400 | Un paramètre requis est manquant (p. ex. code, refresh_token). |
invalid_client | 401 | client_id inconnu, mauvais client_secret, ou app suspendue. |
invalid_grant | 400 | Le code ou refresh token est expiré, révoqué, déjà utilisé, appartient à une autre app, ou la validation PKCE/redirect_uri a échoué. |
unsupported_grant_type | 400 | grant_type doit être authorization_code ou refresh_token. |