Cambiar tema

Guía completa de OAuth en Next.js: Google, GitHub, WeChat y mejores prácticas

Easton editorial illustration: deployment dock

Haces clic en «Iniciar sesión con Google», saltas a Google, autorizas, vuelves y ya estás dentro.

Lo has hecho mil veces. Pero cuando quieres añadir login de terceros a tu proyecto, de repente todo se complica: ¿por qué hay dos redirecciones? ¿Qué es una URL de callback? ¿Qué demonios es redirect_uri_mismatch? ¿Por qué en local va bien y en producción falla?

La primera vez que configuré OAuth leí montones de documentación llena de «código de autorización», access_token y client_secret, y cuanto más leía, peor. Al final tardé dos días y un montón de errores en entenderlo.

En este artículo quiero explicar OAuth con las palabras más directas posibles. Sin amontonar términos ni teoría vacía: cómo funciona de verdad y cómo configurar Google, GitHub y WeChat en Next.js. Cuando lo veas claro, verás que tampoco es tan misterioso.

¿Qué es OAuth 2.0? (Explicado con un ejemplo cotidiano)

Primero, una analogía sencilla

Imagina que vives en una urbanización con portal. Un día compras algo online y quieres que el repartidor lo deje en tu puerta. Problema: hay control de acceso y el repartidor no puede entrar.

¿La forma clásica? Darle tu tarjeta del portal. Pero es arriesgado: si se queda con ella, podría entrar cuando quiera.

La forma más inteligente: vas con el vigilante y dices «tengo un paquete». El vigilante le da al repartidor un pase temporal que dice «solo puede entrar hoy de 14:00 a 16:00, solo al edificio A». Cuando entrega el paquete, el pase caduca.

Esa es la idea central de OAuth.

En esta analogía:

  • = el usuario (quien quiere iniciar sesión)
  • El repartidor = la app de terceros (tu web)
  • El vigilante = el proveedor OAuth (Google, WeChat, GitHub, etc.)
  • La tarjeta del portal = tu contraseña (no se la das a nadie)
  • El pase temporal = access_token (con caducidad y permisos limitados)

No entregas tu contraseña a la app de terceros; solo autorizas que vaya al proveedor OAuth a pedir un «pase temporal».

El flujo OAuth en cinco pasos (modo código de autorización)

Ahora veamos cómo encaja esto en el login OAuth de Next.js.

Paso 1: el usuario hace clic en «Iniciar sesión con Google» en tu web.

Paso 2: tu web redirige al usuario a la página de autorización de Google, con una URL parecida a esta:

https://accounts.google.com/o/oauth2/auth?
  client_id=TuAppID
  &redirect_uri=http://localhost:3000/api/auth/callback/google
  &response_type=code
  &scope=openid email profile
  &state=CadenaAleatoria

Aquí tu web le dice a Google: «Soy la app X (client_id), el usuario quiere entrar con vuestra cuenta; pídele confirmación y, cuando termine, devuélvelo a esta dirección (redirect_uri).»

Paso 3: en Google el usuario ve «La app X quiere acceder a tu información básica» y pulsa «Permitir».

Paso 4: Google redirige de vuelta a tu web (redirect_uri) con un código de autorización (code) en la URL:

http://localhost:3000/api/auth/callback/google?code=ABCD1234&state=CadenaAleatoria

Ojo: ese code es solo un comprobante, no el pase final. Caduca pronto (suele durar unos 10 minutos) y solo sirve una vez.

Paso 5: el backend de tu web lleva ese code, junto con tu client_secret, a Google para cambiarlo por el access_token real:

// Código de backend (simplificado)
const response = await fetch('https://oauth2.googleapis.com/token', {
  method: 'POST',
  body: JSON.stringify({
    code: 'ABCD1234',
    client_id: 'TuAppID',
    client_secret: 'TuAppPassword',
    redirect_uri: 'http://localhost:3000/api/auth/callback/google',
    grant_type: 'authorization_code',
  }),
})

const { access_token } = await response.json()

Con el access_token, tu web puede pedir a Google el email, avatar, nombre, etc.

Paso 6 (opcional): usar access_token para obtener datos del usuario:

const userInfo = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
  headers: {
    Authorization: `Bearer ${access_token}`,
  },
})

Al terminar el flujo, tu web ya sabe «quién es este usuario» y puede crear una sesión para mantenerlo conectado.

Conceptos clave en lenguaje llano

Si aún te suenan raros algunos términos, aquí van en plan sencillo:

  • client_id: el «DNI» de tu app en Google. Puede ser público; no pasa nada si alguien lo ve.

  • client_secret: la «contraseña» de tu app. Nunca debe filtrarse; solo se usa en el backend. Si alguien lo obtiene, puede hacerse pasar por tu app y acceder a datos de usuarios.

  • redirect_uri: la dirección a la que Google devuelve al usuario tras autorizar. Debe estar registrada de antemano en Google Cloud Console. Google la valida al milímetro; hasta una barra de más provoca redirect_uri_mismatch.

  • state: una cadena aleatoria contra ataques CSRF. La generas al iniciar la autorización y Google la devuelve igual. Comprueba que la que vuelve es la misma; si no, la petición puede ser falsa.

  • code: código de autorización temporal. Caduca en unos 10 minutos y solo vale una vez. Sirve para demostrar que el usuario ya autorizó en Google.

  • access_token: el «pase» de verdad. Con él tu web puede obtener información del usuario en Google en su nombre. También caduca, normalmente entre 1 hora y varios días.

¿Por qué code y access_token en dos pasos?

Podrías preguntarte: ¿por qué no devolver directamente el access_token?

Por seguridad. El code viaja en la redirección del navegador (visible en el frontend); el access_token se intercambia servidor a servidor (invisible para el frontend). Si el access_token fuera en la URL, el historial del navegador, logs o monitorización de red podrían filtrarlo. Cambiar code por token exige client_secret, que solo vive en el backend.

Next.js + NextAuth.js: configurar Google (la puerta de entrada más fácil)

¿Por qué NextAuth.js?

Implementar OAuth a mano es pesado: callbacks, sesiones, CSRF, almacenamiento de tokens… muchos detalles.

La buena noticia es NextAuth.js (ahora Auth.js v5). Tiene más de 15k estrellas en GitHub, comunidad activa y soporta más de 50 proveedores OAuth (Google, GitHub, WeChat, Twitter, etc.) casi listos. La versión actual encaja con App Router de Next.js 14+ y es más sencilla que antes.

En la práctica, NextAuth.js te ahorra el 80 % del trabajo repetitivo.

Paso 1: crear la app en Google Cloud

Antes de escribir código, registra tu app en Google y obtén client_id y client_secret.

  1. Abre Google Cloud Console e inicia sesión con tu cuenta de Google.

  2. Si es la primera vez, crea un proyecto. El nombre da igual, por ejemplo «My Next.js App».

  3. En el menú lateral: «APIs y servicios» → «Credenciales».

  4. Pulsa «Crear credenciales» → «ID de cliente de OAuth».

  5. Si es la primera vez, puede pedirte configurar la «Pantalla de consentimiento de OAuth». Pon nombre de la app y email de soporte; el resto puede esperar (tipo de usuario «Externo»; en pruebas no hace falta revisión).

  6. Vuelve a crear el ID de cliente OAuth y elige tipo «Aplicación web».

  7. Aquí está lo importante: en «URIs de redirección autorizados» añade:

    • Desarrollo local: http://localhost:3000/api/auth/callback/google
    • Producción (cuando despliegues): https://yourdomain.com/api/auth/callback/google

    Debe coincidir exactamente con lo que uses en código. Una barra de más o de menos y tendrás redirect_uri_mismatch. Yo caí en eso al principio.

  8. Pulsa «Crear»; aparecerán Client ID y Client Secret. Cópialos; los usarás enseguida.

Paso 2: instalar NextAuth.js y variables de entorno

En tu proyecto Next.js:

npm install next-auth@beta

Instala la versión @beta (v5, la más reciente).

Crea .env.local en la raíz y añade Client ID y Secret:

GOOGLE_CLIENT_ID=TuClient_ID.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=TuClient_Secret
NEXTAUTH_SECRET=GeneraUnaCadenaAleatoria
NEXTAUTH_URL=http://localhost:3000

Genera NEXTAUTH_SECRET con:

openssl rand -base64 32

Al desplegar en producción, cambia NEXTAUTH_URL por tu dominio.

Paso 3: archivo de configuración de NextAuth

Crea app/api/auth/[...nextauth]/route.ts (con Pages Router sería pages/api/auth/[...nextauth].ts):

import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"

export const authOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
  ],
  callbacks: {
    async signIn({ user, account, profile }) {
      // Callback al iniciar sesión; aquí puedes guardar al usuario en la base de datos
      console.log("Usuario conectado:", user)
      return true // true = permitir el login
    },
    async session({ session, token }) {
      // Personalizar el contenido de la sesión
      if (session.user) {
        session.user.id = token.sub // añadir user id a la sesión
      }
      return session
    },
  },
}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

NextAuth.js se encarga de todo el flujo OAuth. La ruta /api/auth/callback/google se genera sola; no hace falta escribirla.

Paso 4: botón de inicio de sesión

En cualquier componente:

'use client' // App Router: componente cliente

import { signIn, signOut, useSession } from "next-auth/react"

export default function LoginButton() {
  const { data: session } = useSession()

  if (session) {
    // Usuario conectado
    return (
      <div>
        <p>Bienvenido, {session.user?.name}</p>
        <img src={session.user?.image || ''} alt="Avatar" />
        <button onClick={() => signOut()}>Cerrar sesión</button>
      </div>
    )
  }

  // Usuario no conectado
  return <button onClick={() => signIn('google')}>Iniciar sesión con Google</button>
}

signIn('google') redirige a Google; tras autorizar vuelve y el usuario queda conectado. Muy simple.

Paso 5: envolver el layout raíz con SessionProvider

Para que useSession funcione en toda la app, envuelve con el Provider:

// app/layout.tsx
import { SessionProvider } from "next-auth/react"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <SessionProvider>{children}</SessionProvider>
      </body>
    </html>
  )
}

Listo: ya tienes una app Next.js con login de Google.

Problemas habituales

Problema 1: redirect_uri_mismatch

Es el error más común; me pasó la primera vez.

El mensaje suele ser: Error 400: redirect_uri_mismatch

Causa: la URL de callback en Google Cloud Console no coincide con la petición real.

Solución:

  1. Comprueba que «URIs de redirección autorizados» sea http://localhost:3000/api/auth/callback/google (sin barras de más)
  2. Comprueba que NEXTAUTH_URL en .env.local sea http://localhost:3000
  3. Si cambiaste el puerto (por ejemplo 3001), actualiza ambos sitios

Problema 2: en local va bien, desplegado falla

También me pasó: en local perfecto, en Vercel el botón no hace nada o da error.

Causa: olvidaste actualizar variables de entorno de producción.

Solución:

  1. En Google Cloud Console añade el dominio de producción: https://yourdomain.com/api/auth/callback/google
  2. En Vercel (o tu plataforma) cambia NEXTAUTH_URL a https://yourdomain.com
  3. Vuelve a desplegar

Problema 3: session es null tras el login

Si useSession() devuelve siempre null, revisa si olvidaste <SessionProvider> en el layout raíz.

Problema 4: TypeError: Cannot read property ‘user’ of null

Suele ocurrir cuando accedes a session.user mientras la sesión aún carga.

Solución: comprueba antes si existe:

const { data: session, status } = useSession()

if (status === 'loading') {
  return <div>Cargando...</div>
}

if (!session) {
  return <div>No has iniciado sesión</div>
}

// Aquí ya puedes usar session.user con seguridad

Configurar GitHub (entender las diferencias)

Con Google ya montado, GitHub es más sencillo. Aun así hay matices respecto a Google.

Diferencias entre OAuth de GitHub y Google

Lo similar: ambos usan el modo código de autorización de OAuth 2.0; el flujo es el mismo.

Lo distinto:

  1. Permisos más granulares: el scope de GitHub es más complejo. Por defecto solo obtienes información pública; para el email (sobre todo privado) hace falta user:email.
  2. Callback más flexible: Google exige la URL completa; GitHub suele bastar con el dominio.
  3. Tipo de app: GitHub admite OAuth App de cuenta personal u organización.

Paso 1: crear OAuth App en GitHub

  1. Inicia sesión en GitHub → avatar → Settings → «Developer settings» en el menú lateral.

  2. «OAuth Apps» → «New OAuth App».

  3. Rellena:

    • Application name: nombre de tu app (lo verá el usuario al autorizar)
    • Homepage URL: home de tu web, por ejemplo http://localhost:3000
    • Authorization callback URL: http://localhost:3000/api/auth/callback/github
  4. «Register application», luego «Generate a new client secret»; copia Client ID y Client Secret.

Paso 2: variables de entorno

En .env.local:

GITHUB_CLIENT_ID=TuGitHub_Client_ID
GITHUB_CLIENT_SECRET=TuGitHub_Client_Secret

Paso 3: actualizar NextAuth

En el mismo route.ts, añade GitHubProvider:

import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import GitHubProvider from "next-auth/providers/github"

export const authOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
    GitHubProvider({
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      // Para email privado, añade esto
      authorization: {
        params: {
          scope: 'read:user user:email'
        }
      }
    }),
  ],
  callbacks: {
    // ... callbacks anteriores
  },
}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

Paso 4: actualizar el botón de login

return (
  <div>
    <button onClick={() => signIn('google')}>Iniciar sesión con Google</button>
    <button onClick={() => signIn('github')}>Iniciar sesión con GitHub</button>
  </div>
)

¡Hecho!

Sobre scope (alcance de permisos)

El scope de GitHub define qué datos puedes leer. Los habituales:

  • read:user: información pública y privada (nombre, avatar, bio, etc.)
  • user:email: correo del usuario (también privado)
  • public_repo: repos públicos del usuario
  • repo: todos los repos (públicos y privados; permiso fuerte, úsalo con cuidado)

Para login basta read:user user:email.

Sin user:email, NextAuth.js solo obtiene el email público. Si el usuario lo ocultó en GitHub, session.user.email será null. A mí me confundió un rato; pensé que era un bug de código.

Un detalle: el usuario de GitHub puede no tener email público

A diferencia de Google (email obligatorio), en GitHub el email puede ser privado. Si tu app lo necesita (notificaciones, etc.), compruébalo en el callback signIn:

async signIn({ user, account }) {
  if (account?.provider === 'github' && !user.email) {
    // Sin email: rechazar login o pedir al usuario que lo complete
    console.log("Usuario de GitHub sin email")
    return false // rechazar login
  }
  return true
}

Configurar WeChat (el caso especial en China)

WeChat es más complejo que Google y GitHub, sobre todo porque su ecosistema no es el mismo que el internacional.

¿Por qué WeChat es distinto?

Puntos clave:

  1. Requiere escanear QR: en web de PC el usuario saca el móvil y escanea (no basta con pulsar en la página como en Google/GitHub).
  2. Sin provider oficial en NextAuth.js: hay que escribir uno personalizado.
  3. Restricciones de callback: el dominio debe estar registrado (ICP); localhost no vale; depurar en local es incómodo.
  4. openid y unionid: el mismo usuario tiene openid distinto en cada app; para unificar usuarios entre apps hace falta unionid.

Paso 1: registro en WeChat Open Platform

  1. Abre WeChat Open Platform y regístrate.

  2. Crea una «aplicación web» (no cuenta oficial ni mini programa).

  3. Rellena datos, sube capturas y espera revisión (1-3 días laborables).

  4. Tras aprobar, obtienes AppID y AppSecret (equivalentes a client_id y client_secret).

  5. En «Información de desarrollo» configura el dominio de callback (solo dominio, sin ruta completa, p. ej. yourdomain.com).

Paso 2: provider personalizado de WeChat

Como NextAuth.js no trae WeChat, créalo en lib/wechat-provider.ts:

import type { OAuthConfig, OAuthUserConfig } from "next-auth/providers"

export interface WeChatProfile {
  openid: string
  nickname: string
  headimgurl: string
  sex: number
  province: string
  city: string
  country: string
  unionid?: string
}

export default function WeChatProvider<P extends WeChatProfile>(
  options: OAuthUserConfig<P>
): OAuthConfig<P> {
  return {
    id: "wechat",
    name: "WeChat",
    type: "oauth",
    
    // URL de autorización WeChat (apps web de PC)
    authorization: {
      url: "https://open.weixin.qq.com/connect/qrconnect",
      params: {
        scope: "snsapi_login",
        appid: options.clientId,
        response_type: "code",
      },
    },
    
    // Intercambiar code por access_token
    token: {
      url: "https://api.weixin.qq.com/sns/oauth2/access_token",
      params: {
        appid: options.clientId,
        secret: options.clientSecret,
        grant_type: "authorization_code",
      },
    },
    
    // Obtener datos del usuario
    userinfo: {
      url: "https://api.weixin.qq.com/sns/userinfo",
      async request({ tokens, provider }) {
        const res = await fetch(
          `${provider.userinfo?.url}?access_token=${tokens.access_token}&openid=${tokens.openid}&lang=zh_CN`
        )
        return await res.json()
      },
    },
    
    // Convertir perfil WeChat al formato NextAuth
    profile(profile) {
      return {
        id: profile.openid,
        name: profile.nickname,
        email: null, // WeChat no proporciona email
        image: profile.headimgurl,
      }
    },
    
    options,
  }
}

Paso 3: variables de entorno

En .env.local:

WECHAT_CLIENT_ID=TuWeChatAppID
WECHAT_CLIENT_SECRET=TuWeChatAppSecret

Paso 4: usarlo en NextAuth

Actualiza route.ts:

import WeChatProvider from "@/lib/wechat-provider"

export const authOptions = {
  providers: [
    GoogleProvider({...}),
    GitHubProvider({...}),
    WeChatProvider({
      clientId: process.env.WECHAT_CLIENT_ID!,
      clientSecret: process.env.WECHAT_CLIENT_SECRET!,
    }),
  ],
}

Paso 5: ¿cómo probar en local?

WeChat no admite localhost como dominio de callback; no puedes probar directo en local.

Dos opciones:

Opción 1: túnel (ngrok, cpolar)

Expón tu servicio local a internet con ngrok o cpolar:

# Instalar ngrok
brew install ngrok

# Iniciar túnel
ngrok http 3000

ngrok te da un dominio temporal, p. ej. https://abc123.ngrok.io. Añádelo en WeChat Open Platform y actualiza NEXTAUTH_URL:

NEXTAUTH_URL=https://abc123.ngrok.io

Opción 2: archivo hosts

En /etc/hosts (Mac/Linux) o C:\Windows\System32\drivers\etc\hosts (Windows):

127.0.0.1 dev.yourdomain.com

Accede a http://dev.yourdomain.com:3000 y configura el dominio en WeChat. Pero WeChat exige dominio registrado (ICP), así que dev.yourdomain.com suele fallar. La opción 1 es más fiable.

Tratamiento especial de WeChat

WeChat no da email. Si tu app lo necesita:

async signIn({ user, account }) {
  if (account?.provider === 'wechat') {
    // Sin email: pedir al usuario que lo complete
    // o usar openid como identificador único en la base de datos
    console.log("openid de usuario WeChat:", user.id)
  }
  return true
}

Mejores prácticas de seguridad (evitar trampas habituales)

Tras configurar OAuth, cuida estos detalles. Yo los aprendí a base de errores.

1. client_secret nunca debe filtrarse

Mal:

// ❌ ¡Nunca hagas esto!
const clientSecret = "abc123def456" // hardcodeado

Si client_secret está en el frontend o en Git, cualquiera puede suplantar tu app.

Bien:

  • Variables de entorno; .env.local en .gitignore
  • client_secret solo en backend (las API routes de NextAuth.js cuentan como backend)
  • En despliegue, variables del panel (Vercel → Settings → Environment Variables)

2. Para qué sirve state (anti-CSRF)

Un atacante puede enviarte un enlace con un code falso. Sin validar state, tu app podría cambiarlo por token.

NextAuth.js valida state automáticamente.

Si implementas OAuth a mano:

  1. Genera state aleatorio al iniciar y guárdalo en sesión o cookie
  2. En el callback, compara el state devuelto con el enviado
  3. Si no coinciden, rechaza

3. Lista blanca de URLs de callback

En Google, GitHub y WeChat, registra todas las URLs posibles:

  • Desarrollo: http://localhost:3000/api/auth/callback/[provider]
  • Preview: https://preview.yourdomain.com/api/auth/callback/[provider]
  • Producción: https://yourdomain.com/api/auth/callback/[provider]

No uses comodines (https://*.yourdomain.com): cómodo pero inseguro. Lista dominios concretos.

4. Seguridad al almacenar tokens

NextAuth.js guarda la sesión en JWT en cookies HttpOnly:

  • HttpOnly: JavaScript del frontend no lee la cookie; reduce robo por XSS
  • Secure (producción): solo por HTTPS; reduce ataques man-in-the-middle

Tu parte:

  • No devuelvas access_token al frontend (NextAuth.js no lo hace por defecto; no lo expongas tú)
  • Si persistes usuarios, hazlo en el callback signIn en base de datos; en sesión solo lo necesario (id, email)

5. Caducidad del código de autorización

El code caduca en ~10 minutos y solo vale una vez.

Aunque alguien lo intercepte, puede que ya esté caducado o usado.

Si el usuario tarda mucho en la pantalla de Google, el code puede expirar. NextAuth.js suele relanzar la autorización.

6. Checklist antes de producción

  • ¿Variables de entorno listas (NEXTAUTH_URL, NEXTAUTH_SECRET, client_id y client_secret de cada provider)?
  • ¿NEXTAUTH_URL apunta al dominio de producción (no localhost)?
  • ¿URLs de callback de producción en cada proveedor OAuth?
  • ¿.env.local en .gitignore?
  • ¿NEXTAUTH_SECRET de producción generado al azar (distinto del de desarrollo)?

Resumen

OAuth, en el fondo, es un «pase temporal»: no das tu contraseña a apps de terceros; autorizas que pidan en el proveedor un token con caducidad y permisos limitados (access_token). Primero el code demuestra que el usuario aceptó; luego code + client_secret obtienen el token real.

En Next.js, Google es lo más fácil para empezar; GitHub un poco más fino (scope y emails no públicos); WeChat el más especial (QR, provider custom, dominio registrado, local incómodo).

En seguridad, tres reglas:

  1. client_secret solo en backend, nunca filtrado
  2. Validar state (NextAuth.js lo hace)
  3. Lista blanca de callbacks, sin comodines

Si es tu primera vez con OAuth, empieza por Google siguiendo el código de este artículo. Cuando funciona, la satisfacción compensa.

Si algo falla, no entres en pánico: el 90 % son redirect_uri mal configurado o variables de entorno faltantes. Repasa y suele resolverse.

Por último, mira la documentación oficial de NextAuth.js (sesión en base de datos, páginas de login custom, JWT, etc.). La especificación OAuth 2.0 (RFC 6749) también ayuda: entender la base facilita depurar.

¡Manos a la obra y mucha suerte con la configuración!

Flujo completo de configuración de inicio de sesión OAuth de terceros en Next.js

Configurar desde cero inicio de sesión con Google, GitHub y WeChat

⏱️ Estimated time: 2 hr

  1. 1

    Step 1: Instalar e inicializar NextAuth.js

    Instalar dependencias:
    • npm install next-auth
    • Crear app/api/auth/[...nextauth]/route.ts

    Configuración básica:
    • Definir NEXTAUTH_URL (local: http://localhost:3000, producción: dominio real)
    • Definir NEXTAUTH_SECRET (generar cadena aleatoria)
    • Configurar el array providers
  2. 2

    Step 2: Configurar inicio de sesión con Google

    Pasos:
    1. Acceder a Google Cloud Console
    2. Crear un ID de cliente OAuth
    3. Definir URI de redirección autorizada: http://localhost:3000/api/auth/callback/google
    4. Obtener Client ID y Client Secret
    5. Añadir a variables de entorno: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
    6. Añadir GoogleProvider en la configuración de NextAuth

    Nota: en producción la URL de callback debe coincidir exactamente con la configurada
  3. 3

    Step 3: Configurar inicio de sesión con GitHub

    Pasos:
    1. Ir a GitHub Settings > Developer settings > OAuth Apps
    2. Crear una OAuth App
    3. Definir Authorization callback URL: http://localhost:3000/api/auth/callback/github
    4. Obtener Client ID y Client Secret
    5. Añadir a variables de entorno: GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET
    6. Añadir GitHubProvider en la configuración de NextAuth

    Nota: el scope debe incluir user:email para obtener el correo
  4. 4

    Step 4: Configurar inicio de sesión con WeChat (opcional)

    Pasos:
    1. Registrar cuenta en WeChat Open Platform (requiere verificación empresarial)
    2. Crear aplicación web y obtener AppID y AppSecret
    3. Configurar dominio de callback autorizado (requiere registro ICP)
    4. Provider personalizado (NextAuth no incluye WeChat)
    5. Implementar flujo de inicio de sesión con código QR

    Nota: WeChat es más complejo; conviene dominar Google y GitHub antes
  5. 5

    Step 5: Crear página y botones de inicio de sesión

    Crear componente de login:
    • Usar signIn('google') para iniciar sesión
    • Usar signOut() para cerrar sesión
    • Usar useSession() para obtener datos del usuario
    • Envolver la app con SessionProvider

    Ejemplo:
    <button onClick={() => signIn('google')}>
    Iniciar sesión con Google
    </button>
  6. 6

    Step 6: Probar y depurar

    Puntos de prueba:
    • Local: asegurar que la URL de callback sea http://localhost:3000
    • Producción: que la URL de callback coincida con el dominio real
    • Comprobar variables de entorno
    • Revisar consola del navegador y logs del servidor

    Errores habituales:
    • redirect_uri_mismatch: URL de callback no coincide
    • invalid_client: Client ID o Secret incorrectos
    • access_denied: el usuario rechazó la autorización

FAQ

¿Cómo funciona OAuth 2.0?
OAuth 2.0 permite que el usuario autorice a apps de terceros a acceder a sus recursos sin dar la contraseña. Flujo: clic en iniciar sesión → redirección al proveedor OAuth → el usuario autoriza → vuelve un código de autorización → se intercambia por access_token → con el token se obtiene la información del usuario.
¿Cómo solucionar el error redirect_uri_mismatch?
Significa que la URL de callback no coincide.

Solución:
1) La URL configurada en el panel del proveedor OAuth debe coincidir exactamente con la del código (protocolo, dominio, puerto y ruta)
2) En desarrollo local usa http://localhost:3000; en producción, el dominio real
3) Revisa barras finales o parámetros extra
¿Qué diferencia hay entre NextAuth.js e implementar OAuth manualmente?
NextAuth.js es una solución OAuth empaquetada:
• Soporta más de 50 proveedores
• Gestiona automáticamente el flujo de autorización, sesiones y protección CSRF

La implementación manual exige manejar:
• Intercambio del código de autorización
• Almacenamiento de tokens
• Validación de state

Mucho más código y propenso a errores; se recomienda NextAuth.js.
¿Cómo obtener el correo del usuario?
Cada proveedor lo hace distinto:
• Google: devuelve el correo por defecto
• GitHub: el scope debe incluir user:email y el usuario debe tener el correo público
• WeChat: hay que consultarlo vía unionid

Si no se obtiene, puedes pedir al usuario que lo complete tras el login.
¿Funciona en local pero falla en producción?
Suele ser un problema de configuración de la URL de callback.

Comprueba:
1) Si NEXTAUTH_URL en producción es correcto
2) Si el panel del proveedor OAuth incluye el dominio de producción
3) Si las variables de entorno están bien definidas
4) Si un firewall o proxy interfiere
¿Se pueden soportar varios métodos de inicio de sesión a la vez?
Sí. NextAuth.js permite configurar varios providers; el usuario puede elegir Google, GitHub, WeChat u otro. En signIn() basta indicar el nombre del provider.
¿Es seguro el inicio de sesión OAuth?
OAuth 2.0 es un estándar de la industria y relativamente seguro.

Pero hay que cuidar:
1) client_secret debe ser confidencial y usarse solo en el servidor
2) Usar el parámetro state contra CSRF (NextAuth.js lo gestiona)
3) Lista blanca de URLs de callback, sin comodines
4) Actualizar dependencias con regularidad

16 min de lectura · Publicado el: 19 dic 2025 · Actualizado el: 21 ago 2026

Comentarios

Inicia sesión con GitHub para dejar un comentario

Easton BlogEaston Blog