Cómo completar el callback OAuth externo
Procesa la vuelta de un proveedor OAuth/OIDC externo, valida la continuidad con `state`, resuelve o crea el usuario de Antylogic, emite cookies de sesión y devuelve al destino `return_to`. No es una pantalla de Antylogic: es una transición HTTP que debe documentarse sin exponer tokens.
En este artículo
El callback externo cierra el flujo iniciado en `GET /api/app/auth/authorize/{provider}`. La ruta no requiere una sesión previa, pero solo continúa si la query `state` coincide con la cookie temporal `oauth_state_{provider}`.
Esta guía está pensada para soporte, administradores y QA que necesitan comprobar accesos externos en un entorno controlado. En capturas es-ES, el destino autenticado recomendado es la home de `Marea Gran Via`, aunque el callback necesita un `code` OAuth real o simulado preparado para documentación.
Antes de empezar
- Existe un registro `auth_providers.code` para `{provider}` y está habilitado con `enabled = true`.
- La vuelta entra como `GET /api/app/auth/callback/{provider}` con query `code` y `state`.
- Existe la cookie temporal `oauth_state_{provider}` y su valor coincide con `state`.
- Si el provider usa PKCE, existe `oauth_pkce_verifier_{provider}` para completar el intercambio.
- El provider puede intercambiar el `code` en su `token_endpoint` y devolver un perfil OIDC con `sub`.
- El auth service acepta el token exchange interno usado por `authclient.Client.IssueSession`.
- Si se resuelve `client_id`, existe el cliente OAuth correspondiente y, si no es first-party, hay consentimiento vigente para los scopes solicitados.
Instrucciones
- 1.
Prepara provider y destino
Comprueba que el provider externo existe y está habilitado. Define el destino operativo con `return_to` en query o con la cookie `oauth_return_to_{provider}`; si no hay destino, el callback usa `APP_BASE_URL` como fallback.
- 2.
Conserva el estado temporal
El flujo válido debe venir de la autorización externa. Antylogic usa cookies namespaced por provider para recuperar `state`, `client_id`, `scopes`, `return_to` y el verificador PKCE cuando aplica.
- 3.
Recibe el callback por GET
El proveedor vuelve a `GET /api/app/auth/callback/{provider}?code={code}&state={state}`. Si falta `code`, el callback responde error; si `state` no coincide, limpia cookies temporales y reinicia hacia `/api/app/auth/authorize/{provider}`.
- 4.
Resuelve el usuario de Antylogic
El backend intercambia el código, construye el perfil OIDC y exige `sub`. Primero busca usuario por provider y subject; si no existe y el email está verificado, puede vincularlo por email; si sigue sin existir, crea un usuario activo con el provider principal.
- 5.
Emite la sesión
Con un usuario activo, el app service pide al auth service una sesión mediante `POST {auth BaseURL}/oauth/token`. El auth service valida cliente, scopes y consentimiento cuando aplica, y emite tokens de acceso y refresco.
- 6.
Vuelve a la superficie operativa
Tras el éxito, el callback escribe `access_token`, `refresh_token` y `auth_session`, limpia cookies temporales OAuth y redirige con `303 See Other`. Para el demo es-ES, la evidencia final debe mostrar `Marea Gran Via` ya autenticada.
- 7.
Usa JSON solo en soporte
Con `redirect=0`, `redirect=false` o `redirect=no`, la ruta devuelve JSON con `status`, `return_to` y `result`. Ese `result` incluye tokens, por lo que cualquier captura o clip público debe enmascarar `result.access_token` y `result.refresh_token`.
Validaciones y límites
- `{provider}` se recorta y se normaliza a minúsculas antes de buscarlo.
- La ruta acepta solo `GET`; no acepta `POST`, body JSON ni formulario.
- `code` y `state` son obligatorios para continuar el callback externo.
- `oauth_state_{provider}` debe existir y coincidir con la query `state`.
- `auth_providers` debe contener el provider y `enabled` debe ser `true`.
- El intercambio OIDC exige `token_endpoint`; si hay `oauth_pkce_verifier_{provider}`, se envía como `code_verifier`.
- El perfil OIDC debe contener `sub`; si falta, el callback devuelve `401 Unauthorized` con `subject requerido`.
- El usuario resuelto debe estar activo; si está desactivado, no se emite sesión.
- `client_id` y `scopes` de query tienen prioridad sobre las cookies temporales; los scopes se separan por coma o espacios.
- Si el cliente OAuth no es first-party, el consentimiento vigente debe cubrir los scopes solicitados.
- El destino `return_to` se toma primero de query, después de `oauth_return_to_{provider}` y por último de `APP_BASE_URL`.
- El handler inspeccionado no valida `return_to` contra una allowlist; revisa destinos absolutos antes de usarlos en documentación o soporte.
- La respuesta de redirección incluye `Cache-Control: no-store, no-cache, must-revalidate`.
- El JSON de éxito no incluye `next` y no debe publicarse con tokens reales visibles.
Resultado esperado
El usuario queda resuelto, las identidades y tokens quedan actualizados en el auth service, Antylogic escribe cookies de sesión y el navegador vuelve al destino configurado. Si se usa modo JSON, el resultado sirve solo para QA o soporte con secretos enmascarados.