Back to flin
flin

OAuth2 y autenticación social

Cómo FLIN proporciona funciones OAuth2 integradas para Google, GitHub, Discord, Apple, LinkedIn y Telegram -- flujos PKCE, validación de estado y creación de usuarios en un patrón estandarizado.

Juste A. Gnimavo (Thales) & Claude | March 26, 2026 5 min flin
EN/ FR/ ES
flinrust

El inicio de sesión social es esperado en toda aplicación web moderna. Los usuarios quieren hacer clic en "Continuar con Google" y autenticarse en segundos, sin crear otra contraseña. Los desarrolladores quieren ofrecer esto, pero la implementación es notoriamente compleja: códigos de autorización OAuth2, URIs de redirección, parámetros de estado, verificadores de código PKCE, intercambios de tokens y peculiaridades específicas de cada proveedor.

En una aplicación Node.js, implementar Google OAuth requiere passport, passport-google-oauth20, configuración de sesiones, rutas de callback y configuración específica del proveedor. GitHub requiere passport-github2 con diferentes alcances y diferentes campos de perfil de usuario. Cada proveedor es un paquete separado con su propia API.

FLIN proporciona funciones integradas para seis proveedores OAuth: Google, GitHub, Discord, Apple, LinkedIn y Telegram. Cada proveedor sigue el mismo patrón de tres pasos: generar la URL de autenticación, manejar el callback y crear o iniciar sesión del usuario.

El patrón universal

Cada proveedor OAuth en FLIN sigue el mismo flujo:

Paso 1: Generar URL de autenticación (página de login)
  auth = auth_PROVIDER_login(baseUrl)
  session.PROVIDERState = auth.state
  <a href={auth.url}>Continue with PROVIDER</a>

Paso 2: Manejar callback (página de callback)
  result = auth_PROVIDER_callback(query.code, query.state, session.PROVIDERState)
  session.PROVIDERState = none

Paso 3: Encontrar o crear usuario
  if result.ok {
      existing = User.where(email == result.user.email).first
      if existing != none { iniciar sesión }
      else { crear nuevo usuario }
  }

Los nombres de funciones, el patrón de almacenamiento en sesión y la lógica de encontrar-o-crear son idénticos en todos los proveedores. Aprenda uno y los conocerá todos.

Google OAuth con PKCE

Google es el proveedor OAuth más utilizado. FLIN lo implementa con PKCE (Proof Key for Code Exchange), la extensión de seguridad recomendada para clientes públicos:

flin// app/login.flin -- Paso 1: Generar URL de autenticación

baseUrl = env("BASE_URL") || "http://localhost:3000"
googleAuth = auth_google_login(baseUrl)

// Almacenar estado y verificador PKCE en sesión
session.googleState = googleAuth.state
session.googleRedirectUri = googleAuth.redirect_uri
session.googleCodeVerifier = googleAuth.code_verifier

// Renderizar el botón de login
<a href={googleAuth.url} class="social-btn">
    Continue with Google
</a>

La función auth_google_login() genera: - Un parámetro state aleatorio (protección CSRF) - Un code_verifier y code_challenge (PKCE) - La URL de autorización completa con alcances, URI de redirección y tipo de respuesta

flin// app/auth/google/callback.flin -- Paso 2: Manejar callback

layout = "auth"

result = auth_google_callback(query.code, query.state, session.googleState)
session.googleState = none

authOk = false

fn processGoogleAuth() {
    if result.ok {
        existing = User.where(email == result.user.email && role == "User").first
        if existing != none {
            session.user = existing.email
            session.userName = existing.name || result.user.name
            session.userId = to_text(existing.id)
        } else {
            newUser = User {
                email: result.user.email,
                name: result.user.name,
                provider: "Google",
                providerId: to_text(result.user.id),
                avatar: result.user.avatar || "",
                emailVerified: true
            }
            save newUser
            session.user = newUser.email
            session.userName = newUser.name
            session.userId = to_text(newUser.id)
        }
        authOk = true
    }
}
processGoogleAuth()

{if authOk}
    <h2>Welcome!</h2>
    <script>setTimeout(function() { window.location.href = "/tasks"; }, 1000);</script>
{else}
    <h2>Authentication failed</h2>
    <a href="/login">Try again</a>
{/if}

El objeto de resultado OAuth

Cada función auth_*_callback() retorna la misma estructura:

flin// Éxito
result.ok              // true
result.user.id         // ID de usuario del proveedor
result.user.email      // Email (puede ser none para algunos proveedores)
result.user.name       // Nombre para mostrar
result.user.avatar     // URL de imagen de perfil
result.user.provider   // "google", "github", etc.

// Fallo
result.ok              // false
result.error           // Descripción del error

Esta interfaz consistente significa que la lógica de encontrar-o-crear es idéntica para cada proveedor. Las únicas diferencias están en los nombres de variables de sesión y la configuración de la página de login.

Seguridad: estado y PKCE

Cada flujo OAuth en FLIN está protegido por dos mecanismos:

Parámetro de estado. Una cadena aleatoria almacenada en la sesión e incluida en la URL de autorización. El callback verifica que el estado en la respuesta coincida con el estado en la sesión. Esto previene ataques CSRF donde un atacante engaña a un usuario para que se autentique con la cuenta del atacante.

PKCE (Proof Key for Code Exchange). Se genera un verificador de código aleatorio y su hash SHA-256 (el desafío de código) se envía con la solicitud de autorización. Al intercambiar el código de autorización por tokens, se envía el verificador de código original. El servidor de autorización verifica que el hash coincida. Esto previene ataques de intercepción de códigos de autorización.

rustfn generate_pkce() -> (String, String) {
    let verifier = generate_random_string(64);
    let challenge = base64url_encode(&sha256(verifier.as_bytes()));
    (verifier, challenge)
}

Ambas protecciones se generan y verifican automáticamente por las funciones auth_<em>_login() y auth_</em>_callback(). El desarrollador almacena el estado y el verificador en la sesión pero nunca necesita entender por qué.

Por qué importa el OAuth integrado

OAuth2 es un estándar, pero los detalles de implementación varían enormemente entre proveedores. Google requiere PKCE. Apple envía un POST. GitHub podría no retornar un email. Discord usa nombres de alcance diferentes. LinkedIn ha deprecado múltiples versiones de API.

Al absorber estas diferencias en funciones integradas, FLIN asegura que: 1. Cada implementación OAuth sigue el estándar correctamente. 2. Las medidas de seguridad (estado, PKCE) siempre se aplican. 3. Las peculiaridades del proveedor se manejan internamente. 4. La interfaz del desarrollador es consistente en todos los proveedores.

La alternativa -- instalar una biblioteca separada para cada proveedor, configurar cada una de manera diferente y esperar que todas manejen la seguridad correctamente -- es exactamente el tipo de complejidad que FLIN fue diseñado para eliminar.

En el próximo artículo, cubrimos la autenticación OTP por WhatsApp -- el método de autenticación diseñado específicamente para el mercado africano donde la identidad basada en teléfono es más común que el email.


Esta es la Parte 111 de la serie "Cómo construimos FLIN", que documenta cómo un CEO en Abidjan y un CTO de IA diseñaron y construyeron un lenguaje de programación desde cero.

Navegación de la serie: - [110] Autenticación de dos factores (TOTP) - [111] OAuth2 y autenticación social (estás aquí) - [112] Autenticación OTP por WhatsApp para África - [113] Validadores de cuerpo de solicitud

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles

Thales & Claude zerosuite

Funciona, y no está terminado

El director recorrió él mismo todos los canales de senndo — cinco canales, de uno en uno y en campaña, la importación, las estadísticas, un reembolso, la API — y todo respondió. El archivo de seguimiento seguía diciendo que no, y la única línea que bloqueaba no era código: era un documento que había dejado de ser cierto en silencio. Cuatro afirmaciones ciertas al escribirse y falsas al leerse, y las guardas legibles por una máquina que ahora atrapan cada una de esas formas.

12 min Sep 14, 2026
senndocpaaslaunch-readinessdocumentation +8
Thales & Claude zerosuite

El navegador en manos de Claude: manejar el propio Chrome del CEO

Claude-in-Chrome permite que una sesión de Claude Code maneje el navegador real del director — mismo perfil, mismas sesiones abiertas. Qué hace la herramienta en realidad, por qué es mejor que pedirle a una persona que haga clic y lo cuente, y dónde el humano sigue ganando. Anclado en el día en que Claude recorrió un alta de cliente completa en la consola de producción de senndo, con mensajes facturados incluidos.

9 min Aug 18, 2026
claude-in-chromebrowser-automationclaude-codeclaude-fable-5 +9
Thales & Claude deblo

El segfault que no era nuestro: cómo lanzamos el tracking del día de lanzamiento de Déblo en la noche del despliegue — analítica condicionada por entorno, atribución nativa de las tiendas, tres bugs que el compilador no podía ver y un build sin memoria que diagnosticamos en lugar de revertir

El 1 de julio de 2026 — el día del lanzamiento — el riesgo nunca fue el texto. Era que las campañas de pago salieran a ciegas. Este es el build-log de cómo desplegamos la analítica y la atribución de instalaciones de Déblo como código en la noche del lanzamiento: etiquetas GA4, Meta y LinkedIn condicionadas por entorno que se despliegan sin riesgo antes de que existan las cuentas publicitarias; atribución enrutada por los canales nativos de las tiendas en lugar del pixel web; una auditoría adversarial que atrapó tres bugs que tanto el typechecker como el build dieron por buenos; y un despliegue en Easypanel que hizo segfault en el primer build — que demostramos que no era nuestro código antes de tocar una sola línea.

18 min Jul 1, 2026
deblolaunch-dayclaude-opus-4.8claude-code +26