Autenticación

Apps OAuth

Para apps que actúan en nombre de otros usuarios de Gravl. OAuth 2.0 authorization-code estándar con PKCE: los usuarios conceden a tu app scopes concretos, tú obtienes tokens de acceso de corta duración con un token de refresco rotatorio, y el grant es revocable en cualquier momento.

1. Registra tu app

El registro es manual mientras la API está en beta. Escribe a developers@gravl.ai con:

  • El nombre de tu app y una breve descripción de lo que hace
  • Tu(s) redirect URI(s) de OAuth: URLs https absolutas (http://localhost permitido para desarrollo)
  • Los scopes que necesita tu app; pide el mínimo, los usuarios ven exactamente lo que solicitas

Recibirás un client_id (gci_…) y un client_secret (gcs_…, se muestra una sola vez; guárdalo como una contraseña).

2. Envía al usuario a la pantalla de consentimiento

GET /oauth/authorize
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=S256

El usuario inicia sesión con su cuenta de Gravl, ve el nombre de tu app y los scopes solicitados en lenguaje claro, y aprueba; su navegador vuelve a tu redirect_uri con ?code=gac_…&state=… (o error=access_denied si cancela).

  • Los códigos llevan el prefijo gac_, son válidos 10 minutos, de un solo uso, y están ligados a tu app y a la redirect_uri para la que se emitieron
  • PKCE (S256) es obligatorio para clientes públicos (apps de navegador o nativas, que no tienen client_secret) y muy recomendable para todos
  • Verifica siempre que state coincide con lo que enviaste: es tu protección CSRF

Los clientes públicos omiten client_secret en el endpoint de token; PKCE es su autenticación de cliente. Dinos de qué tipo es tu app al registrarla.

3. Intercambia el código

POST /oauth/token — authorization_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"
}
TokenVida útilNotas
access_token6 horasToken bearer para las peticiones a /api/v1.
refresh_tokenHasta 180 díasDe un solo uso: cada refresco lo revoca y emite un par nuevo (rotación).

4. Refresca

POST /oauth/token — refresh_token
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 respuesta tiene la misma forma que el intercambio del código. El token de refresco presentado se revoca en la misma transacción: persiste siempre el nuevo refresh_token antes de descartar el antiguo. Reutilizar un token de refresco ya usado devuelve invalid_grant.

5. Revoca

POST /oauth/revoke
curl -X POST https://api.gravl.ai/oauth/revoke \
  -d token=grt_… \
  -d client_id=gci_… \
  -d client_secret=gcs_…
  • Revocar un token de acceso mata solo ese token
  • Revocar un token de refresco revoca el grant completo: todos los tokens vigentes para ese par usuario + app
  • Según la RFC 7009 el endpoint devuelve 200 incluso para tokens desconocidos; solo unas credenciales de cliente incorrectas producen un error
  • Los usuarios también pueden revocar el acceso de tu app desde su cuenta

Errores del endpoint de token

Los errores siguen la RFC 6749: { "error": "…", "error_description": "…" }:

ErrorEstadoSignificado
invalid_request400Falta un parámetro obligatorio (p. ej. code, refresh_token).
invalid_client401client_id desconocido, client_secret incorrecto o la app está suspendida.
invalid_grant400El código o el token de refresco expiró, fue revocado, ya se usó, pertenece a otra app, o falló la validación de PKCE/redirect_uri.
unsupported_grant_type400grant_type debe ser authorization_code o refresh_token.