Autenticación
Una cabecera, un formato de token, y cuatro rechazos que responden igual a propósito.
Una integración lleva su llave en una cabecera, y ninguna de sus peticiones se responde sin ella.
Authorization: Bearer ulg_live_...El token
Un token es ulg_live_ seguido de 32 caracteres hexadecimales. El prefijo es lo
que lo hace reconocible en un log o en un texto pegado, y eso es lo que permite
rastrear filtraciones.
Solo se guarda un hash del token. Nadie, ni nosotros, puede leer una llave después de creada: la columna que guarda el hash no se concede a ningún rol que hable con la API, así que una consulta que la alcance se rechaza incluso para su propio dueño.
Qué significa un rechazo
Una llave desconocida, revocada, expirada o malformada responden todas lo
mismo: 401 invalid_key. No se distinguen a propósito, para que un token no
pueda ser sondeado hasta descubrir de qué modo está mal.
Una llave viva que no tiene el permiso responde 403 insufficient_scope, y el
cuerpo nombra el permiso que faltó:
{
"error": {
"code": "insufficient_scope",
"message": "This key does not hold library.write.",
"scope": "library.write"
}
}Hasta dónde alcanza una llave
La petición corre como la cuenta dueña de la llave. Una llave con lists.write
en una cuenta que no puede escribir en cierta lista privada sigue sin poder,
porque quien rechaza es la regla de la lista, no el permiso.
Un permiso es un techo. Estrecha lo que la llave puede intentar; nunca amplía lo que su dueño puede hacer.
El sitio entra por el mismo lugar
uloggd no habla con la base de datos por fuera de su propia API: cada botón del sitio llama a estas mismas rutas. Lo que lleva es la cookie de sesión de quien inició sesión, y no una llave, porque una llave que el sitio se diera a sí mismo sería una que nadie podría revocar.
Eso cambia tres cosas, y solo tres:
- Una sesión no tiene permisos. Es la cuenta misma, así que
403 insufficient_scopenunca le ocurre. - Una sesión no gasta la cuota de ninguna llave, y la respuesta no trae
X-RateLimit-*. Los límites que la cuenta ya tenía siguen valiendo. - En
/api/v1/me,keyvienenull.
Una cookie solo se acepta cuando la petición viene del mismo origen, porque una cookie viaja sola y una cabecera no. Una llave no pasa por esa comprobación: solo llega si alguien la escribió.
Cuando la cabecera está, es ella la que decide. Una llave revocada responde
401 invalid_key aunque el navegador también lleve una sesión válida:
presentar una llave es decir qué identidad se quiere, y una llave que sigue
funcionando tras ser revocada, mientras quien la creó esté dentro, es una
revocación que nadie puede probar.
Rutas solo para sesión
Algunas rutas responden solo a una sesión del propio sitio, nunca a una llave, porque una llave no puede ganar más poder del que recibió ni tocar la cuenta que la creó:
- todo lo que está bajo
/api/v1/account: las aplicaciones y las llaves, las sesiones, el estado y la preparación de la cuenta, la exportación, los datos, el nombre de usuario, la fecha de nacimiento, las identidades y las conexiones, y toda ruta de desarrollador y de jugador de Arcade, incluidas las de la URL de desarrollo (GET,PUTyDELETE /api/v1/account/apps/{id}/arcade/override); - las imágenes del layout del perfil (
/api/v1/profile/layout/media), que gastan el espacio de la propia cuenta; - la denuncia de un juego de Arcade (
POST /api/v1/reportscononARCADE_APP).
Una llave recibe 403 forbidden en ellas. Las de Arcade están en
Recursos: Arcade. Las de la URL de
desarrollo también piden una sesión verificada con la verificación en dos
pasos, incluso para leer (consulta
La URL de desarrollo).
Cuidar una llave
- Trátala como una contraseña, porque es una que se salta la contraseña.
- Dale una llave a cada integración. Revocar una no le cuesta nada a las demás.
- Revócala en la pestaña Llaves de la aplicación, en el portal, en cuanto una llave se escape. La revocación vale ya en la petición siguiente.