State cookie was missing, y cuando un "Workaround" parece la única salida
Cuando desarrollamos aplicaciones, cada línea de código es como una pequeña pieza en un puzle intrincado. Cada pieza debe encajar perfectamente para que el cuadro completo funcione como se espera. Pero, ¿qué sucede cuando nos encontramos con una pieza que simplemente no parece encajar, sin importar cómo la giremos o la volteamos? Nos enfrentamos a una decisión crítica: ¿buscamos una solución rápida que haga que la pieza encaje por el momento o nos detenemos para considerar por qué la pieza no encaja en primer lugar?
La historia que estás a punto de leer es un caso de estudio de un dilema real. Este relato ofrece una visión de los desafíos que enfrentamos, las decisiones que tomamos y las implicaciones de esas decisiones. No es solo una historia sobre código, sino también sobre personas, procesos y, finalmente, sobre cómo nos enfrentamos a los problemas que inevitablemente surgen en nuestro viaje por el laberinto del desarrollo de software.
El Contexto
En una reciente implementación, un desarrollador se enfrentó a un desafío. Se le asignó la tarea de agregar un botón de registro a una aplicación web que, al ser presionado, debería redirigir a los usuarios hacia una página de registro utilizando FusionAuth. La aplicación en cuestión utilizaba las bibliotecas next-auth
y @fusionauth/typescript-client
. Si bien estas herramientas ofrecen enlaces directos para iniciar sesión, no proporcionaban un método directo para el registro.
La solución parecía inicialmente simple: redirigir al usuario a /oauth2/register?
y enviar algunos parámetros vía query string. Y de hecho, el primer intento de redirección funcionó. Pero al retornar el control hacia la aplicación cliente, se enfrentó a un error:
[next-auth][error][OAUTH_CALLBACK_ERROR]
https://next-auth.js.org/errors#oauth_callback_error State cookie was missing
La Solución
A pesar de los esfuerzos y múltiples intentos, el desarrollador no pudo encontrar la raíz del problema. Sin embargo, finalmente encontró una solución práctica: generó un enlace para iniciar sesión y simplemente reemplazó authorize
por register
en la URL resultante. El registro funcionó y todo parecía resolverse. Pero, ¿era realmente una solución o solo un parche temporal?
Parte del código que resolvío el problema se ve de la siguiente manera:
const handleSignUp = async () => {
const csrfResponse = await fetch('/api/auth/csrf');
const { csrfToken } = await csrfResponse.json();
const signInWithFusionAuthResponse = await fetch('/api/auth/signin/fusionauth', {
method: 'POST',
body: new URLSearchParams({
csrfToken,
callbackUrl: '/retomando_el_control',
json: 'true',
}),
});
const { url } = await signInWithFusionAuthResponse.json();
// esta línea hace toda la magia
window.location.href = url.replace('authorize', 'register');
};
Donde /api/auth/signin
y /api/auth/csrf
son manejados automáticamente por la librería next-auth, entonces en la estructura de archivos del proyecto, se ve como pages/api/auth/[...nextauth].ts
y dentro se encuentra toda la lógica para manejar FusionAuth con NextAuth.
Si te sientes identificado con este problema, hay una discusión abierta en GitHub sobre este error específico.
¿Solución rápida o investigación profunda?
Aquí es donde las cosas se complican. En el desarrollo, a menudo nos enfrentamos a este tipo de decisiones. ¿Deberíamos optar por una solución improvisada o invertir tiempo en entender el problema a fondo? Aquí hay algunas consideraciones:
- Durabilidad: ¿La solución resistirá cambios futuros?
- Mantenibilidad: Las soluciones rápidas pueden ser difíciles de entender para futuros revisores.
- Seguridad: Es vital asegurarse de que no se comprometa la seguridad.
- Aprendizaje: Resolver problemas nos hace crecer profesionalmente.
- Tiempo y Recursos: Hay que equilibrar entre resolver ahora y posibles problemas futuros.
Yo personalmente creo que siempre es necesario dedicar un poco más de tiempo en los problemas, entenderlos y si es posible corregirlos también, es verdad que la librería que introduce el problema no es nuestra, pero si es algo viniendo de la comunidad, también es una buena forma de retribuir a la comunidad nuestra ayuda, resolviendo problemas comunes.
El papel de los Managers
Los managers juegan un papel crucial en estos escenarios. Deben entender que no toda solución rápida es la mejor a largo plazo. Es fundamental tener una perspectiva equilibrada y brindar el apoyo necesario para que los desarrolladores puedan investigar y aprender.
Conclusión
El desarrollo de software no es solo sobre código; es también sobre la toma de decisiones. En ocasiones, la ruta más rápida puede ser la adecuada, pero es vital considerar el panorama general. Y si tienes un equipo de desarrollo a tu cargo, recuerda dar a tu equipo el espacio y los recursos para crecer y aprender, incluso si eso significa invertir un poco más de tiempo en el presente.
Nuestra historia concluye con un problema que aunque fue resuelto queda un sabor extraño de que se pudo haber logrado resolver de una forma diferente y óptima (aunque también sabemos que óptimo es algo relativo), pero con valiosas lecciones sobre la resolución de problemas y la toma de decisiones en el desarrollo de software. Así que, la próxima vez que te encuentres en una situación similar, ¡recuerda esta historia y piensa en el panorama completo!
Happy coding! :D
Photo by Brendan Church on Unsplash