Flujo Authorization Code + PKCE
El flujo Authorization Code + PKCE es el patrón OAuth 2.0 recomendado para todas las aplicaciones que autentican usuarios reales. Esta página explica qué es PKCE, por qué se introdujo y cómo funciona el flujo completo de principio a fin — incluyendo las propiedades de seguridad en cada paso.
Por qué existe PKCE
El flujo Authorization Code original de OAuth 2.0 (sin PKCE) tiene una vulnerabilidad de seguridad en clientes públicos: la interceptación de código.
Cuando Auris redirige de vuelta a tu aplicación con un código de autorización, ese código viaja a través de la barra de URL del navegador. En dispositivos móviles, una aplicación maliciosa registrada para gestionar el mismo esquema URI personalizado podría interceptar la redirección. Incluso en aplicaciones web, el código puede aparecer en logs de servidor, encabezados de referencia o historial del navegador.
Si un atacante intercepta el código, puede canjearlo por tokens en el endpoint de tokens. En el flujo clásico, nada lo impediría.
PKCE (Proof Key for Code Exchange, RFC 7636) soluciona esto vinculando el código de autorización a la sesión de cliente específica que lo solicitó. Solo el cliente que generó originalmente el code verifier puede canjear el código — incluso si un atacante tiene el código.
Auris aplica PKCE en todos los flujos de código de autorización. El método de desafío plain es rechazado — solo se acepta el método S256 (SHA-256). No hay forma de omitir PKCE en Auris.
El mecanismo PKCE
PKCE añade dos valores al flujo estándar:
Code Verifier: Una cadena aleatoria criptográficamente segura, de 43-128 caracteres, usando solo caracteres URL no reservados (A-Z, a-z, 0-9, -, ., _, ~). Este valor se mantiene secreto por el cliente.
Code Challenge: Una versión transformada del code verifier, calculada como:
code_challenge = BASE64URL(SHA256(ASCII(code_verifier)))El cliente envía el code challenge (el hash) al endpoint de autorización. Al canjear el código, el cliente envía el code verifier sin procesar. Auris recalcula el challenge y confirma que coincide. Como un atacante no puede revertir un hash SHA-256, no puede falsificar el verifier.
Flujo paso a paso
Paso 1: Generar el Code Verifier
El cliente genera un code_verifier criptográficamente aleatorio. Debe tener entre 43 y 128 caracteres del alfabeto [A-Za-z0-9-._~].
function generateCodeVerifier(): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'
const array = new Uint8Array(64)
crypto.getRandomValues(array)
return Array.from(array)
.map(b => chars[b % chars.length])
.join('')
}
const codeVerifier = generateCodeVerifier()
// Ejemplo: "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"Almacena el code_verifier en sessionStorage (no en localStorage) — solo necesita sobrevivir al viaje de redirección.
Paso 2: Derivar el Code Challenge
Calcula SHA-256(code_verifier) y codifica el resultado en Base64URL:
async function generateCodeChallenge(verifier: string): Promise<string> {
const encoder = new TextEncoder()
const data = encoder.encode(verifier)
const digest = await crypto.subtle.digest('SHA-256', data)
return btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '')
}
const codeChallenge = await generateCodeChallenge(codeVerifier)
// Ejemplo: "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"Paso 3: Redirigir al endpoint de autorización
Construye la URL de autorización e inicia la redirección:
GET https://auth.yourdomain.com/api/oauth/authorize
?response_type=code
&client_id=app_xxxxx
&redirect_uri=https://yourapp.com/callback
&scope=openid+profile+email
&state=random-csrf-token
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256| Parámetro | Requerido | Descripción |
|---|---|---|
response_type | Sí | Siempre code |
client_id | Sí | Client ID de tu aplicación |
redirect_uri | Sí | Debe coincidir exactamente con una URL de callback registrada |
scope | Sí | Debe incluir openid |
state | Recomendado | Token CSRF aleatorio para prevenir ataques CSRF |
code_challenge | Sí | El hash SHA-256 Base64URL del code verifier |
code_challenge_method | Sí | Siempre S256 |
Paso 4: El usuario se autentica
Auris muestra la página de login alojada. El usuario introduce sus credenciales, completa cualquier factor MFA requerido y aprueba los scopes solicitados.
Paso 5: Auris redirige de vuelta con el código
Tras la autenticación exitosa, Auris redirige al redirect_uri con un código de autorización de un solo uso:
https://yourapp.com/callback?code=auth_code_xyz&state=random-csrf-tokenPaso 6: Intercambiar el código por tokens
El cliente envía el código más el code verifier original al endpoint de tokens:
POST /api/auth/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=auth_code_xyz
&redirect_uri=https://yourapp.com/callback
&client_id=app_xxxxx
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXkAuris recalcula el code challenge desde el verifier y lo compara con el challenge almacenado. Si coinciden, emite los tokens.
Paso 7: Recibir los tokens
{
"access_token": "eyJhbGciOiJSUzI1NiJ9...",
"token_type": "Bearer",
"expires_in": 900,
"refresh_token": "rt_7fKp2mXa9qN3vB8yR4tL1wC6jD5sE0uH",
"id_token": "eyJhbGciOiJSUzI1NiJ9...",
"scope": "openid profile email"
}Los SDK de Auris (JavaScript, React, Next.js, PHP) gestionan todos los pasos de generación de PKCE, almacenamiento del verifier, intercambio de código y gestión de tokens automáticamente. Solo necesitas llamar a loginWithRedirect() y handleRedirectCallback().