Configurando Next Auth en Next.js 13.4
Configuración base para usar NextAuth en un proyecto Next.js versión 13.4, con Signin página/template por defecto e implementación OAuth Google.
Contexto
Estos días comencé un nuevo proyecto con next 13.4 (hasta hace poco solo venía utilizando la 12 a causa de que la 13 > estaba todavía en beta su famoso App router).
Creo que una de las herramientas más poderosas y con gran popularidad en el ambiente de Next es Next auth, por lo cual, para implementarlo en mi proyecto, tuve que investigar de que manera interactúan estás dos tecnologías en sus versiones actuales, y a la vez, cuales son las nuevas técnicas y propuestas que Next 13.4 trae de nuevo (pero hablar sobre esto último haría el post muy extenso, así que es un tema que va a quedar pendiente).
En este blog me centro en dar una idea base sobre como configurar Next auth en Next 13, usar la página/template que Next Auth crea automaticamente para hacer signin, validar la sesión del usuario desde un Server Component y utilizar OAuth de google para autenticar una cuenta.
Next Auth
Next auth es un servicio que nos permite hacer de la autenticación de los usuarios de nuestro sitio algo seguro y sencillo para ellos y con una implementación rápida y amigable para nosotros, los desarrolladores. Siendo una de las mejores alternativas, estos últimos años fue ganando mucha popularidad entre la comunidad y en conjunto con ello, es mayor el suporte/ayuda que se puede encontrar en los foros de internet respecto a esta tecnología.
Let's start!
Paso 1. Instalación
Lo primero que haremos es crear una nueva Next app. Para este ejemplo debemos elegir la opción `src/directory` que next nos ofrece al instalarlo.
terminal
npx create-next-app@latest
Luego instalamos next-auth
terminal
npm i next-auth
o
yarn add next-auth
Paso 2. Estructura de carpetas.
Al finalizar las instalaciones deberiamos tener una estructura de carpetas similar a esta:
Llegados a este punto base, tenemos que decirle a Next en donde podrá encontrar el punto de acceso para comenzar a interactuar con Nextauth.
Por lo cual agregaremos la siguiente estructura de carpetas dentro src:
/pages/api/auth/[...nextauth.ts]
Paso 3. Archivo [...nextauth].ts
Como comentaba antes, Next debe encontrar la forma de comunicarse con todos los metodos y servicios que ofrece nextauth, y de esa forma, obtener toda la magía para hacer nuestros login. En este punto entra el archivo [...nextauth].ts, en el cual determinaremos nuestros metodos de login, el theme para las páginas como signin/signout/emailverification que vienen por defecto en el servicio, manejo de callbacks, jwt, etc.
Importante: nextAuth, nos ofrece sus páginas/templates para hacer nuestro signin/signout/emailverification pero sin embargo, en cuanto modifiquemos valores en el objeto pages de nuestro authOptions, estas páginas quedaran desactivadas. También es bueno aclarar que podemos customizar algunas cosas de estos template, como el colorScheme, que en el código que esta debajo tiene el valor dark, por lo cual, veremos el template en darkmode
[...nextauth].ts
import NextAuth from "next-auth";
import { AuthOptions } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
export const authOptions = {
providers: [
GoogleProvider({
clientId: String(process.env.GOOGLE_CLIENT_ID)!,
clientSecret: String(process.env.GOOGLE_CLIENT_SECRET)!
})
],
theme: {
colorScheme: "dark",
logo: "/logo.svg"
},
secret: String(process.env.NEXTAUTH_SECRET)
} as AuthOptions;
export default NextAuth(authOptions);
Paso 4. Comprobar.
Llegados a este punto ya podríamos intentar ver algo de novedad en nuestro sitio. Para ello, en app/page.tsx agregaremos el siguiente codigo
page.tsx
import Link from "next/link";
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<Link href="/api/auth/signin">Go to login</Link>
</main>
);
}
Si hacemos click en Go to login, lo que deberia aparecer es
Paso 5. OAuth Google
Como podrán haber notado cuando se hace click en el boton Sign in with google, obtenemos un error, y eso esta bien porque todavía no configuramos nuestro .env file. Para configurarlo, primero debemos crear este archivo .env en el root de nuestro proyecto, es decir, en /.
Ahora debemos declarar en el .env las Variables de Entorno:
.env
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
Los valores de las variables que declaramos anteriormente los podemos obtener del siguiente link: GoogleConsole .
En cuanto estén dentro de la página, buscán un boton que diga Crear nuevo proyecto y luego generan las credenciales para un ID de cliente de OAuth.
Algo importante a tener en cuenta es configurar los origenes autorizados y también la URI de redireccionamiento, debería quedarles algo así:
Paso 6. Si todo salio ok.
Si todo salio ok, luego de autenticarse con su usuario de Google, deberían encontrarse en el mismo lugar del comienzo, osea en /app/page.tsx
.
Paso 7. Verificar usuario autenticado.
Ya tenemos al usuario autenticado dentro de nuestro sitio. Ahora bien, necesitamos evitar que otros usuarios que no pasaron por nuestro metodo de autenticación ingresen a nuestra app. Para ello, dado que estamos utilizando Next 13, vamos a utilizar el metodo de NextAuth getServerSession(), dentro de nuestro server component Home (app/page.tsx).
Resultado:
page.tsx
import { authOptions } from "@/pages/api/auth/[...nextauth]";
import { getServerSession } from "next-auth";
import Link from "next/link";
import { redirect } from "next/navigation";
export default async function Home() {
const session = await getServerSession(authOptions);
if (!session) {
redirect("/api/auth/signin");
}
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<Link href="/api/auth/signin">Go to login</Link>
</main>
);
}
Paso 8. Comprobar nuevamente.
Teniendo listo el login y la validación para usuarios no autenticados, nos falta todavía comprobar que esto funcione correctamente. Para esto vamos a hacer que el usuario pueda cerrar su sesión y intentaremos entrar en la ruta localhost:3000 .
Lo primero que haremos es crear un componente con el nombre de Logout, el cual contendrá un elemento button y estará dentro de la carpeta components.
Logout.tsx
"use client";
import { signOut } from "next-auth/react";
export const LogoutButton = () => {
return (
<button style={{ marginRight: 10 }} onClick={() => signOut()}>
Sign Out
</button>
);
};
Actualizamos nuestra Home Page
page.tsx
import { LogoutButton } from "@/components/Logout";
import { authOptions } from "@/pages/api/auth/[...nextauth]";
import { getServerSession } from "next-auth";
import Link from "next/link";
import { redirect } from "next/navigation";
export default async function Home() {
const session = await getServerSession(authOptions);
if (!session) {
redirect("/api/auth/signin");
}
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div className="flex gap-8">
<Link href="/api/auth/signin">Go to login</Link>
<LogoutButton />
</div>
</main>
);
}
Ya podemos testear que todo funcione correctamente, si apretamos en el boton Sign out, nos debería redireccionar a localhost:3000/api/auth/signin y si intentamos ingresar a localhost:3000 sin autenticarnos, nuestro código hará su magia 🧙♂️