Tema representativo de entrevista

Entrevista de Backend: Explicar el flujo Authorization Code con PKCE en OAuth

BackendDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Tu producto necesita que los usuarios autoricen el acceso a una API de calendario de terceros. Explica el flujo completo de OAuth 2.0 authorization code con PKCE para un cliente público, incluidos los parámetros clave, las responsabilidades de state y PKCE, la validación en el servidor, clientes públicos frente a confidenciales y el límite entre OAuth y OpenID Connect.

Problema y contexto de aplicación

Tu producto necesita leer un calendario de terceros en nombre de un usuario sin manejar la contraseña de dicho calendario. Explica el flujo completo de OAuth 2.0 authorization code con PKCE para un cliente público, incluyendo lo que deben validar el backend de la aplicación y el servidor de autorización.

Asume que el cliente es una aplicación de página única (SPA) de navegador o una aplicación nativa. No puede mantener de forma fiable una credencial estática confidencial en todas las instancias desplegadas, por lo que es un cliente público. El servidor de autorización autentica al usuario, recopila el consentimiento y emite tokens. El servidor de recursos expone la API del calendario. El scope inicial es acceso de solo lectura al calendario; la emisión del refresh token depende de la política del servidor de autorización.

Una guía pública de entrevistas de backend publicada en marzo de 2026 pide a los candidatos explicar el grant de authorization code, PKCE, clientes públicos y confidenciales, y el límite entre OAuth y OpenID Connect. La base de seguridad actual es el OAuth 2.0 Security Best Current Practice: los clientes públicos deben usar PKCE, también se recomienda su uso para clientes confidenciales, los servidores de autorización deben prevenir el downgrade de PKCE y las redirect URIs registradas requieren coincidencia exacta.

Esta es una pregunta de backend porque la habilidad central radica en diseñar y validar un protocolo de autorización entre servicios, los límites de tokens y los controles de seguridad. Las redirecciones del navegador son solo su medio de transporte.

Qué evalúa el entrevistador

Primero, ¿puede el candidato separar los cuatro roles? El resource owner es el usuario, el cliente es el producto agregador de calendarios, el servidor de autorización maneja la autenticación, el consentimiento y la emisión de tokens, y el servidor de recursos es el dueño de los datos del calendario. Confundir al cliente con el usuario hace que cualquier afirmación posterior sobre permisos y audiencias de tokens se desvíe.

Segundo, ¿puede el candidato explicar por qué el flujo authorization code tiene dos tramos? El navegador solo recibe un authorization code de un solo uso y corta duración. El cliente lo intercambia en el token endpoint, de modo que el access token no viaja en una URL de redirección del navegador. Luego, PKCE vincula un secreto aleatorio creado para la solicitud de autorización a ese intercambio de código. Una parte que intercepte el código pero carezca del code_verifier aún no podrá canjearlo.

Tercero, ¿puede el candidato mantener precisa la responsabilidad de cada control?

ControlVinculación principalProblema principal abordado
stateSesión del cliente que inicia hacia el callbackCorrelación de solicitudes y CSRF de inicio de sesión
PKCESolicitud de autorización al intercambio de tokensIntercepción de código e inyección de código
Autenticación de clienteCliente confidencial al servidor de autorizaciónIdentidad del cliente que canjea el código
Redirect URI exactaCliente registrado al callback permitidoEntrega del código a un endpoint controlado por un atacante
OIDC nonceSolicitud de inicio de sesión al ID TokenReplay de ID Token y correlación de sesión de inicio de sesión

Finalmente, una respuesta sólida expone el límite de PKCE. No impide que un XSS del mismo origen lea un verifier o un token. No reemplaza a TLS, la validación de redirecciones, el principio de menor privilegio, el almacenamiento seguro de tokens ni un protocolo de autenticación.

Preguntas de clarificación antes de responder

  • ¿El cliente es público o confidencial? Una SPA o app nativa no puede probar su identidad con un client secret estático. Una aplicación web con un backend controlado puede ser confidencial y debe autenticarse en el token endpoint además de usar PKCE.
  • ¿El objetivo es la autorización de API o el inicio de sesión en el producto? El acceso a la API del calendario usa OAuth. Si el producto necesita la identidad del usuario, usa OIDC y valida un ID Token en lugar de inferir la identidad a partir de un access token.
  • ¿El cliente utiliza un solo servidor de autorización o proveedores de identidad configurados por inquilino (tenant)? Múltiples emisores requieren validación de emisor o redirect URIs distintas para evitar ataques de mix-up.
  • ¿Se requiere acceso sin conexión (offline access)? No solicites un refresh token cuando no sea necesario. Si es obligatorio, define rotación, detección de replay, revocación y expiración.
  • ¿Dónde se almacena el estado de la transacción del callback? Preserva una vinculación de state → code_verifier. Un único verifier global rompe el funcionamiento de pestañas concurrentes; colocarlo en una URL o registro de logs destruye el secreto.
  • ¿Cuánto acceso al calendario se necesita? Comienza con el scope de solo lectura requerido por la funcionalidad. Los permisos de escritura o a nivel de toda la cuenta necesitan una justificación concreta.

Marco de respuesta de 30 segundos

“Para cada intento de autorización, genero un state impredecible y un code_verifier de alta entropía, luego derivo un code_challenge S256. El navegador va al authorization endpoint con response_type=code, client ID, una redirect URI registrada exactamente, scope mínimo, state y challenge. El usuario se autentica únicamente en el servidor de autorización. El callback devuelve un código de corta duración de un solo uso y el mismo state. El cliente valida el state, carga el verifier de esa transacción y envía el código, la redirect URI y el verifier al token endpoint. El servidor emite un access token solo después de validar el código, el cliente, la redirect URI y la vinculación del challenge. Un cliente público no puede tratar un secreto estático como una credencial; un cliente confidencial también se autentica. PKCE protege el intercambio de código, state correlaciona la solicitud y un ID Token de OIDC es lo que respalda la identidad de inicio de sesión.”

Análisis detallado paso a paso

Paso uno: crear una transacción de autorización de un solo uso.

Para cada acción de “conectar calendario”, el cliente genera dos valores aleatorios independientes:

  • state es un ID de transacción imposible de adivinar vinculado a la sesión actual del usuario, el emisor esperado, la URI de callback y el destino posterior a la autorización.
  • code_verifier se genera con una fuente aleatoria criptográficamente segura. La RFC 7636 lo define como de 43 a 128 caracteres no reservados y recomienda al menos 256 bits de entropía.

El cliente deriva el challenge de la siguiente manera:

text
code_challenge = base64url_without_padding(
  SHA256(ASCII(code_verifier))
)
code_challenge_method = S256

Almacena un registro de state → code_verifier separado para cada transacción. Dos pestañas del navegador pueden iniciar dos conexiones de calendario concurrentemente, por lo que “el último verifier” no es un modelo de datos válido. Asigna a la transacción una expiración corta y elimínala tras el éxito o fallo terminal. No incluyas el verifier en URLs de redirección, eventos de analítica o logs de la aplicación.

Paso dos: construir la solicitud de autorización.

El cliente envía el agente de usuario al authorization endpoint:

text
GET /authorize
  ?response_type=code
  &client_id=calendar-client
  &redirect_uri=registered-callback
  &scope=calendar.read
  &state=random-transaction-id
  &code_challenge=derived-challenge
  &code_challenge_method=S256

El servidor de autorización valida el client ID, response type, scope y redirect URI. La redirect URI debe coincidir exactamente con un valor preregistrado en lugar de un dominio amplio, subruta arbitraria o parámetro de reenvío controlado por el usuario. Las credenciales del usuario se envían únicamente al servidor de autorización. El cliente recibe un resultado de autorización, nunca la contraseña del usuario.

Paso tres: procesar el callback sin llamar al token endpoint todavía.

Tras el consentimiento, el servidor de autorización redirige al agente de usuario al callback registrado con code y el state original. El cliente primero valida su transacción local:

  1. El state existe, no ha expirado y no ha sido consumido.
  2. Está vinculado a la sesión actual del navegador y al servidor de autorización esperado.
  3. El callback llegó al endpoint registrado para esta transacción.
  4. Una respuesta de error aún puede usar state para encontrar y terminar de forma segura la transacción correcta.

Aborta en caso de discrepancia de state en lugar de “probar la solicitud de token para ver si funciona”. El authorization code debe ser de corta duración y de un solo uso. Un intento de canje repetido debe fallar, y el servidor de autorización debe revocar los tokens ya emitidos a partir de ese código cuando sea posible.

Paso cuatro: intercambiar el código con el verifier.

El cliente envía esta solicitud de token:

text
POST /token

grant_type=authorization_code
code=returned-authorization-code
redirect_uri=registered-callback
client_id=calendar-client
code_verifier=stored-verifier

El servidor de autorización reconstruye la transacción original: a qué cliente y redirect URI pertenece el código, si está expirado o ya fue utilizado, si la solicitud de autorización contenía un challenge y si aplicar S256 a este verifier es igual al challenge almacenado. Si la solicitud de autorización carecía de challenge pero la solicitud de token presenta un verifier, el servidor no debe degradar silenciosamente la transacción a un flujo sin PKCE.

Un cliente público envía un client ID para identificación, pero un secreto estático distribuido en código público no puede autenticarlo. Un cliente confidencial utiliza adicionalmente su método registrado de autenticación de clientes. PKCE complementa esa autenticación en lugar de reemplazarla.

Paso cinco: explicar cada control a través de una ruta de ataque.

Supongamos que el cliente legítimo crea el verifier V1 y el challenge C1. Un atacante intercepta el código del callback pero no conoce V1. Un verifier elegido por el atacante no produce C1, por lo que el intercambio de tokens falla. Esa es la protección principal de PKCE contra la intercepción del authorization code.

Ahora supongamos que el atacante inicia una transacción de autorización separada e inyecta ese código en el callback de la víctima. La transacción de la víctima tiene un state y verifier diferentes. La correlación de state o la vinculación de PKCE fallan, y el cliente debe abortar. El servidor de autorización también debe recordar si había un challenge presente para un código, evitando que un atacante elimine el challenge y provoque un downgrade.

Si un atacante cambia la redirect URI a un endpoint bajo su control, el registro exacto y la coincidencia exacta de strings lo rechazan durante la autorización. Si un cliente admite múltiples servidores de autorización, también debe comparar el emisor de la respuesta con el emisor guardado en la transacción o usar una redirect URI distinta para cada emisor. Recordar únicamente la URL del authorization endpoint no es suficiente para prevenir el mix-up.

Paso seis: restringir los tokens a su propósito real.

Un access token representa autorización y no es una aserción de identidad de usuario para el cliente. El servidor de recursos verifica que el token esté destinado a él y lo limita a los recursos y acciones requeridos. El cliente solicita únicamente calendar.read, utiliza access tokens de corta duración y mantiene los tokens fuera de URLs, logs y almacenamientos persistentes accesibles para scripts no relacionados.

PKCE ha completado su trabajo después de que el código se convierte en token. Si un XSS puede leer la memoria de la SPA, el almacenamiento de la transacción o un access token, PKCE no puede recuperar el secreto. Una aplicación de navegador de mayor riesgo puede utilizar un BFF: los tokens permanecen en un backend controlado y el navegador mantiene una cookie de sesión HttpOnly. Esto reduce la exposición del token a JavaScript, pero añade costos de sesión en cookies, CSRF, escalabilidad del backend y proxies de API.

Si un cliente público recibe refresh tokens, el servidor de autorización debe detectar el replay mediante restricción del remitente (sender constraint) o rotación de refresh tokens. Con la rotación, cada refresco emite un nuevo refresh token e invalida el anterior. La reutilización de un valor antiguo indica un posible compromiso, por lo que la familia de grants se revoca y el usuario debe autorizar de nuevo.

Paso siete: separar OAuth, OIDC y otros grants.

OAuth responde si un cliente puede acceder a un recurso en nombre de un usuario. OIDC añade una capa de identidad sobre OAuth para que el cliente pueda verificar un inicio de sesión mediante un ID Token. Un callback de OIDC también requiere validación de firma, emisor, audiencia, expiración y nonce. Un access token está destinado al servidor de recursos; un ID Token está destinado al cliente. No son intercambiables.

Usa client credentials cuando no participe ningún usuario y un servicio acceda a recursos bajo su propia autoridad. Un dispositivo con capacidades de entrada limitadas puede usar un device authorization flow. El flujo implícito (implicit flow) coloca un access token en la respuesta de autorización, lo que incrementa la fuga en URLs y la exposición al replay; las mejores prácticas actuales favorecen un flujo que devuelva código. El grant de resource owner password credentials expone la contraseña del usuario al cliente y está prohibido por la base de seguridad actual.

Paso ocho: validar los fallos, no solo el camino feliz (happy path).

PruebaResultado esperado
Cambiar un carácter del verifierEl intercambio de tokens falla
Canjear el mismo código dos vecesEl segundo intercambio falla y activa el manejo de seguridad
El state del callback falta, expiró o pertenece a otra sesiónEl cliente rechaza antes del intercambio de tokens
La autorización omite un challenge pero la solicitud de token envía un verifierEl servidor de autorización rechaza el downgrade
La redirección difiere solo por mayúsculas/minúsculas, ruta o barra finalLa coincidencia exacta falla
Dos pestañas inician flujos y los callbacks regresan desordenadosCada state recupera su propio verifier
Intercambiar emisores tras conectar dos servidores de autorizaciónEl cliente rechaza el mix-up
Escanear logs y analíticaNo aparece ningún código, verifier, access token ni refresh token
Un XSS lee el almacenamiento accesible por el navegadorSe juzga explícitamente a PKCE como insuficiente; evaluar un BFF

La monitorización en producción debe distinguir entre denegación de autorización, discrepancia de state, fallo de PKCE, reutilización de código, discrepancia de redirección y replay de refresh tokens. Un único contador genérico de “fallo de OAuth” oculta tanto las señales de ataque como los defectos de implementación del cliente.

Ejemplo de respuesta de alta calidad

“Definiré el alcance de esto como un cliente público que accede a una API de calendario de terceros. No puede proteger un secreto compartido, por lo que un secreto embebido en un paquete de SPA no constituye autenticación de cliente.

Al inicio de cada autorización, genero un state impredecible y un code verifier con al menos 256 bits de entropía, derivo un challenge S256 y almaceno el verifier, la sesión del navegador, el emisor, la redirect URI y la expiración bajo ese state. La solicitud de autorización lleva el response type code, el client ID, la redirect URI registrada exactamente, el scope de solo lectura, el state y el challenge. El usuario se autentica y otorga su consentimiento únicamente en el servidor de autorización.

Cuando el callback devuelve el código y el state, primero demuestro que el state pertenece a la sesión actual y no ha sido utilizado, luego cargo su verifier. La solicitud de token envía el código, la misma redirect URI, el client ID y el verifier. El servidor de autorización verifica que el código sea de corta duración, no haya sido usado, esté emitido para este cliente y redirect URI, y que el valor S256 del verifier coincida con el challenge antes de emitir un access token. Un código interceptado es inútil sin el verifier. El servidor también rechaza una solicitud que intente eliminar PKCE y degradar el intercambio.

State correlaciona la solicitud del navegador, mientras que PKCE vincula el intercambio de código; no los colapsaría en un único parámetro CSRF impreciso. Una aplicación web confidencial también se autentica en el token endpoint y debería conservar PKCE. El access token es solo para el servidor de recursos de calendario. Si el producto utiliza el flujo para inicio de sesión, necesita OIDC y debe validar la firma, emisor, audiencia, expiración y nonce del ID Token.

Probaría un verifier incorrecto, reutilización de código, state de sesiones cruzadas, discrepancia exacta de redirección, pestañas fuera de orden, downgrade de PKCE y mix-up de emisores, además de verificar que los logs no contengan códigos ni tokens. PKCE no puede evitar que un XSS del mismo origen robe un verifier o un token. Para un cliente de navegador de alto riesgo, evaluaría un BFF que almacene tokens en el servidor y entregue al navegador solo una cookie de sesión HttpOnly.”

Errores comunes

  • Tratar el client ID como un secreto → el client ID aparece en las solicitudes de autorización y solo identifica al cliente → usa PKCE para un cliente público y autenticación de cliente real para un cliente confidencial.
  • Decir únicamente que “un código es más seguro que un token” → esto no explica por qué un código interceptado no puede ser canjeado → muestra la vinculación challenge-verifier y la comparación en el token endpoint.
  • Usar plain o permitir que se omita PKCE → el verifier puede quedar expuesto o un atacante puede forzar un downgrade → usa S256 y haz que el servidor de autorización registre y aplique PKCE de forma obligatoria.
  • Generar state sin vincularlo a una sesión → se pueden trasplantar valores válidos y los flujos concurrentes se sobreescriben entre sí → almacena un mapeo de un solo uso de state, sesión, emisor y verifier.
  • Permitir coincidencia de redirección difusa (fuzzy) → un código puede llegar a una subruta o redireccionador controlado por un atacante → preregistra y compara exactamente las redirect URIs.
  • Decodificar un access token y tratarlo como identidad de inicio de sesión → su audiencia y semántica pueden pertenecer al servidor de recursos → usa inicio de sesión con OIDC y valida el ID Token.
  • Afirmar que PKCE detiene ataques XSS → XSS puede leer un verifier, código o token emitido directamente → reduce la exposición de tokens en el navegador, corrige el XSS y evalúa un BFF según el nivel de riesgo.
  • Registrar códigos, verifiers o tokens en logs → los diagnósticos amplían la exposición de secretos canjeables → registra IDs de transacción, clases de error y valores de correlación no canjeables.

Preguntas de seguimiento y respuestas

Pregunta de seguimiento 1: ¿Una aplicación web tradicional con backend todavía necesita PKCE?

Sí. La autenticación de clientes en el token endpoint demuestra que un cliente confidencial posee su credencial protegida. PKCE vincula esta solicitud de autorización a este intercambio de código y protege adicionalmente contra la inyección y el uso indebido de códigos. Los controles vinculan relaciones diferentes. La sesión en el servidor puede almacenar el verifier y el state mientras que el navegador solo transporta un identificador de sesión impredecible.

Pregunta de seguimiento 2: ¿Qué cambia si “conectar calendario” también significa “iniciar sesión con calendario”?

Utiliza OIDC en lugar de tratar un access token o una respuesta UserInfo arbitraria como prueba de inicio de sesión. Solicita el scope openid y un nonce. Valida la firma, el emisor, la audiencia, la expiración y el nonce del ID Token; luego utiliza el par emisor-sujeto (issuer-subject) como la clave de identidad externa. State continúa vinculando la transacción del navegador; nonce vincula la solicitud de autenticación al ID Token.

Pregunta de seguimiento 3: ¿Qué nuevo riesgo aparece cuando cada inquilino de SaaS configura un emisor diferente?

El cliente puede enviar una respuesta del servidor de autorización A al token endpoint del servidor de autorización B, provocando un ataque de mix-up. Guarda el emisor esperado en la transacción y valida el emisor de la respuesta. Otra defensa consiste en usar una redirect URI distinta por emisor y verificar que la respuesta haya llegado al endpoint correcto. Los endpoints de autorización y de token deben provenir de los metadatos del mismo emisor de confianza.

Pregunta de seguimiento 4: ¿Cómo proteges los refresh tokens para una sincronización de calendario de larga duración?

Otorga solo los scopes requeridos y usa rotación de refresh tokens o restricción del remitente (sender constraint). Con la rotación, rastrea la familia de tokens: cada refresco invalida el valor anterior, y la reutilización de un refresh token antiguo revoca la familia activa y requiere una nueva autorización. El cliente también necesita almacenamiento seguro, una ruta de revocación, una vida útil máxima y expiración por inactividad. PKCE protege el intercambio de código inicial, no un refresh token robado con posterioridad.

Pregunta de seguimiento 5: ¿Por qué dos pestañas que conectan diferentes cuentas de calendario fallan intermitentemente?

Una causa común es tener un único state o verifier global: la segunda pestaña sobreescribe a la primera. El callback debe buscar una transacción independiente mediante state. Ese registro contiene el verifier, la cuenta o emisor esperado, la redirect URI y la marca de tiempo de creación. Consúmelo de forma atómica. Rechaza states desconocidos, duplicados y expirados en lugar de recurrir al verifier más reciente.

Fuentes públicas

Preguntas relacionadas