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.

Thales & Claude | March 30, 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