Proveedores OAuth
Reglas
- Usar flujo de Código de Autorización con PKCE para clientes públicos (SPA, móviles) — nunca flujo Implícito
- Intercambio de código del lado del servidor para aplicaciones web — el secreto del cliente nunca sale del servidor
- Parámetro
state: generar state aleatorio, almacenar en sesión/cookie, verificar en el callback — previene CSRF
- Google OAuth: alcances
openid email profile, usar id_token para información del usuario
- GitHub OAuth: alcance
read:user user:email, intercambiar código en https://github.com/login/oauth/access_token
- Discord OAuth: alcance
identify email, endpoint de token en https://discord.com/api/oauth2/token
- Renovación de token: almacenar
refresh_token en el servidor, renovar antes de que expire access_token
- Gestión de sesiones: crear sesión de aplicación al recibir el callback OAuth exitoso, no almacenar tokens OAuth en cookies
- Vincular cuentas: permitir a los usuarios conectar múltiples proveedores a una cuenta mediante la tabla
accounts
Patrones
export async function GET(req: Request) {
const { searchParams } = new URL(req.url);
const code = searchParams.get("code");
const state = searchParams.get("state");
if (state !== cookies().get("oauth_state")?.value) {
return new Response("Estado inválido", { status: 400 });
}
const tokens = await exchangeCodeForTokens(code);
const userInfo = await fetchUserInfo(tokens.access_token);
const user = await upsertUser(userInfo);
await createSession(user.id);
return redirect("/dashboard");
}
Evitar
- Almacenar secretos de cliente en código frontend — siempre intercambiar tokens del lado del servidor
- Omitir el parámetro
state — los ataques CSRF son reales
- Almacenar tokens OAuth sin procesar en cookies — usar sesiones del lado del servidor
- Olvidar manejar el caso de "el usuario ya existe con ese correo" al vincular proveedores