Connexion Google avec Auth.js et Prisma : Intégrer les guides Next.js ensemble
Combinez les guides Prisma et Auth.js pour Next.js en une application fonctionnelle permettant la connexion via Google, avec des utilisateurs persistants et des publications liées à la session, y compris les corrections que les documents omettent.
Sources: Prisma + NextAuth setup for NextJS
Ajouter des comptes et des données enregistrées à une application Next.js ne nécessite pas de backend distinct. Avec Auth.js (le successeur de NextAuth) pour l’authentification, Prisma en tant que ORM et une base de données Postgres hébergée comme Neon, le même projet Next.js peut gérer les connexions, les sessions et la persistance des données. Chaque outil dispose de son propre guide détaillé pour Next.js, mais ces guides diffèrent quant aux structures de dossiers, se réfèrent à des conventions obsolètes et ne montrent jamais comment les éléments s’interconnectent. Cette démarche suit ces guides dans l’ordre et indique chaque ajustement nécessaire, afin que vous obteniez une fonction de connexion via Google, des utilisateurs stockés dans Postgres et des articles attribués à l’utilisateur connecté.
Pourquoi conserver l’authentification et les données à l’intérieur de l’application Next.js
Une configuration courante pour un produit qui commence comme outil principalement côté client consiste en un backend distinct, par exemple Django avec Postgres et un fournisseur d’identité hébergé comme Auth0. Cela fonctionne, mais cela implique un deuxième service à déployer, à surveiller et pour lequel il faut payer. Lorsqu’un petit produit a besoin d’ajouter des fonctionnalités telles que des workflows enregistrés, réutiliser le serveur Next.js pour l’authentification et l’accès à la base de données permet de réduire les coûts d’hébergement et le nombre de composants à gérer. Le compromis est que vous devez alors assurer l’intégration entre trois bibliothèques, ce dont traite le reste de cet article.
Ces paquets évoluent rapidement. Auth.js pour Next.js est encore publié sous une version bêta, et tant Prisma que Next.js ont modifié leurs paramètres par défaut dans les dernières versions majeures. Considérez les étapes ci-dessous comme un guide et vérifiez les détails dans la documentation actuelle de chaque projet.
Installation de Prisma sans les fonctionnalités supplémentaires hébergées
Le guide Prisma pour Next.js est rédigé en tenant compte de Prisma Postgres, la base de données hébergée par l’entreprise. Si vous prévoyez d’utiliser une autre version de Postgres, vous pouvez omettre @prisma/extension-accelerate, car il n’est utile que pour cette offre hébergée.
Pour une configuration classique avec Postgres, vous avez besoin de deux installations : la CLI et tsx en tant que dépendances de développement, ainsi que le client et dotenv en tant que dépendances de runtime. Le fragment montre les deux commandes sur une même ligne ; exécutez-les l’une après l’autre :
npm install prisma tsx --save-dev npm install @prisma/client dotenv
Ensuite, initialisez Prisma dans le projet :
npx prisma init
Le guide mentionne également un paramètre --db pour init. Ce paramètre configure une instance de Prisma Postgres, il faut donc l’omettre lorsque vous utilisez votre propre base de données.
Pour faire fonctionner une base de données localement sans installer Postgres, Prisma peut démarrer un serveur de développement pour vous :
npx prisma dev
Étape init : une valeur de DATABASE_URL a déjà été écrite dans votre fichier .env, indiquant ce serveur local. Si vous exécutez déjà Postgres localement, ou que vous souhaitez pointer vers une branche Neon, remplacez cette valeur par votre propre chaîne de connexion. Pour en savoir plus sur le comportement de Prisma 7 dans un projet Next.js 16, y compris le nouveau fichier de configuration, consultez notre guide de configuration Prisma 7.
Création de l’application d’exemples posts
Le reste du guide Prisma consiste à créer un petit blog avec des utilisateurs et des articles. Si vous ajoutez Prisma à une application existante, vous pouvez sauter directement à la section d’authentification. Cependant, il est utile de suivre le guide, car les étapes ultérieures partent du principe que ces modèles existent déjà.
Commencez par ajouter les modèles dans schema.prisma comme décrit pour l’étape de schéma, puis chargez les variables d’environnement dans la configuration Prisma comme indiqué pour l’étape dotenv.
Résolution du chemin d’importation du client généré
Lorsque vous initialisez la base de données, le script d’initialisation tel qu’il est écrit importe directement depuis le dossier prisma généré, ce qui échoue. Le code généré expose le client sous une entrée nommée client, donc la première ligne d’importation du script d’initialisation doit pointer vers cet endroit :
import { PrismaClient, Prisma } from "../app/generated/prisma/client";
L’alias @/app fonctionne tout aussi bien que le chemin relatif ../app.
La même correction s’applique lorsque vous configurez le client Prisma partagé dans lib/prisma.ts:
import { PrismaClient } from '../app/generated/prisma/client'
Le guide alterne également entre les conventions src/app et simple app/ d’une étape à l’autre. Choisissez celle que votre projet utilise réellement : avec une racine src/, le chemin est ../src/app/generated ; sans elle, ../app/generated. La plupart des erreurs « module not found » à ce stade proviennent d’un mélange des deux.
Lorsque le client est en place, ajoutez les pages décrites dans le guide : la requête pour la page d’accueil, la liste des articles, la page de détail d’un article et le formulaire pour en créer de nouveaux.
Ajout d’Auth.js
Il existe deux sites de documentation pour cette bibliothèque : l’ancien site NextAuth et le plus récent référentiel Auth.js pour Next.js. La documentation d’Auth.js décrit la version actuelle et doit être suivie.
Installez le paquet depuis son canal bêta :
npm install next-auth@beta
Ensuite, exécutez npx auth secret. Cela génère un AUTH_SECRET aléatoire, que Auth.js utilise pour signer et chiffrer les tokens et les cookies, puis l’écrit dans .env.local. Comme ce projet conserve déjà ses variables dans .env, déplacez la valeur là-bas et supprimez .env.local afin d’avoir une seule source de configuration. Gardez ce fichier en dehors du contrôle de version.
Suivez maintenant les étapes d’installation. L’élément central est un fichier auth.ts situé dans la racine du projet. Il appelle NextAuth une fois et exporte quatre outils utilisés par le reste de l’application : les handlers HTTP, signIn, signOut et auth, qui lit la session actuelle :
import NextAuth from "next-auth"
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [],
})
Le gestionnaire de route situé sous ./app/api/auth/[...nextauth]/route.ts se contente de réexporter les gestionnaires GET et POST afin que Auth.js puisse gérer ses points d’entrée pour l’authentification, les rappels et les sessions. Dans cet extrait, le commentaire et l’export se trouvent sur la même ligne ; dans votre fichier, placez l’export sur une ligne distincte après l’import :
import { handlers } from "@/auth" // Referring to the auth.ts we just created export const { GET, POST } = handlers
Le guide d’installation ajoute également un fichier middleware.ts. Depuis, Next.js a renommé le middleware en proxy (voir la note de Next.js sur ce changement), de sorte que le fichier décrit ne correspond plus à la version actuelle de Next.js. Vous n’avez pas besoin de ce fichier pour cette configuration, car chaque page et action protégées vérifie directement la session. Si vous souhaitez ultérieurement une protection au niveau de la requête, adaptez-la à la convention du proxy.
Connexion de Google en tant que fournisseur d’authentification
Dans la Google Cloud Console, créez un client OAuth de type application web. Définissez l’origine JavaScript autorisée sur localhost:3000 et l’URL de redirection sur localhost:3000/api/auth/callback/google, qui correspond à la route de rappel exposée par Auth.js pour le fournisseur Google. Lors du déploiement, ajoutez également l’origine et la route de rappel en environnement de production. Stockez le ID du client ainsi que le secret fournis par Google dans votre fichier d’environnement sous les noms de variables indiqués dans la documentation d’Auth.js, et jamais dans le code source.
La guide OAuth ajoute ensuite un composant de connexion. Il s’agit d’un formulaire dont l’action est une action serveur intégrée appelant signIn:
import { signIn } from "@/auth"
export function SignIn() {
return (
<form
action={async () => {
"use server"
await signIn()
}}
>
<button type="submit">Sign in</button>
</form>
)
}
Lorsqu’il est appelé sans arguments, signIn() dirige l’utilisateur vers la page intégrée qui liste tous les fournisseurs configurés. Étant donné que seul Google est configuré, l’envoi de "google" permet d’éviter cet écran intermédiaire.
Un composant de déconnexion correspondant, issu des documents de gestion des sessions, suit la même structure :
import { signOut } from "@/auth"
export function SignOut() {
return (
<form
action={async () => {
"use server"
await signOut()
}}
>
<button type="submit">Sign Out</button>
</form>
)
}
Placer les boutons dans une barre de navigation
Les documents ne précisent pas où placer ces composants. Un endroit naturel est une barre de navigation qui est elle-même un composant serveur asynchrone : celui-ci appelle auth() et affiche SignOut en présence d’un utilisateur, ainsi que SignIn dans le cas contraire.
import Link from "next/link";
import { auth } from "../auth"
import SignIn from "./sign-in";
import SignOut from "./sign-out";
export default async function Navigation() {
const session = await auth();
return (
<>
<nav className="sticky top-0 z-50 bg-white/80 backdrop-blur-md border-b border-gray-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center h-16">
{/* Logo */}
<Link href="/" className="flex items-center space-x-2">
<span className="text-xl font-semibold text-[#369b6f]">
Prisma + NextAuth + Neon
</span>
</Link>
{/* Spacer */}
<div className="flex-1"></div>
{/* Navigation Links */}
<div className="hidden md:flex items-center mr-8">
<Link
href="/posts"
className="text-gray-700 font-medium hover:text-[#369b6f] transition-all duration-200"
>
Posts
</Link>
</div>
{/* Auth Buttons */}
<div className="flex items-center space-x-2 sm:space-x-4">
{session?.user ? (
<SignOut/>
) : (
<SignIn/>
)}
</div>
</div>
</div>
</nav>
</>
);
}
Prêtez attention aux importations ici : ce fichier utilise des importations par défaut pour SignIn et SignOut, tandis que les composants ci-dessus utilisent des exports nommés. Modifiez soit les importations en import { SignIn } from "./sign-in", soit exportez les composants en tant que valeurs par défaut ; sinon la compilation échouera.
Ensuite, affichez la navigation dans le layout racine afin qu’elle apparaisse sur toutes les pages :
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body>
<Navigation/>
<main>
{children}
</main>
</body>
</html>
);
}
N’oubliez pas d’importer Navigation en haut de app/layout.tsx. Une fois que le serveur de développement a été rechargé, une barre contenant des boutons de connexion et de déconnexion apparaît au-dessus de chaque page. Gardez à l’esprit que ces boutons reposent sur des actions serveur en ligne, ce qui les rend fonctionnels uniquement à l’intérieur de composants serveur. Un composant client ne peut pas définir de fonctions serveur en ligne ; dans ce cas, vous devrez placer ces actions dans un fichier séparé marqué de "use server" et les importer.
Stockage persistant des utilisateurs avec l’adaptateur Prisma
Jusqu’à présent, la connexion fonctionne, mais aucune information sur l’utilisateur n’est stockée dans votre base de données. L’adaptateur Prisma relie Auth.js à votre client Prisma afin que les utilisateurs, les comptes OAuth associés et les sessions soient enregistrés dans Postgres. Installez-le :
npm install @auth/prisma-adapter
Ensuite, mettez à jour auth.ts pour transmettre l’adaptateur ainsi que votre client Prisma partagé, et enregistrez le fournisseur Google :
import NextAuth from "next-auth"
import Google from "next-auth/providers/google"
import { PrismaAdapter } from "@auth/prisma-adapter";
import prisma from "@/lib/prisma";
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [Google],
})
Avec un adaptateur configuré, Auth.js stocke par défaut les sessions dans la base de données plutôt que dans un cookie signé, ce qui vous permet de révoquer les sessions du côté serveur au prix d’une recherche dans la base de données à chaque vérification de session. Le fournisseur Google récupère automatiquement ses identifiants depuis les variables d’environnement dès qu’elles respectent la convention de nommage d’Auth.js.
Conciliation du modèle Utilisateur
L’adaptateur nécessite des tables et des colonnes spécifiques, listées dans le schéma de l’adaptateur Prisma. Copiez-les dans schema.prisma. Cela entre en conflit avec l’application d’exemple : le guide Prisma a créé un modèle User avec son propre type d’id, tandis qu’Auth.js attend un id de type chaîne ainsi que plusieurs champs supplémentaires. Pour un projet d’exemple vierge, la solution la plus simple consiste à remplacer le modèle et à reconstruire la base de données depuis zéro. Si vous intégrez cet adaptateur dans une application qui dispose déjà d’utilisateurs réels, ne rien réinitialiser ; planifiez plutôt une migration appropriée qui associe les utilisateurs existants à la nouvelle structure. Il s’agit d’un problème distinct hors du champ d’application de cette démarche.
Pour reconstruire proprement, arrêtez d’abord l’exécution de la séquence de données initiales, car ces données font référence à l’ancienne structure des utilisateurs. Supprimez l’entrée correspondante dans prisma.config.ts :
seed: `tsx prisma/seed.ts`
Puis réinitialisez la base de données, ce qui supprime toutes les tables et les données :
npx prisma migrate reset
Exécutez cela uniquement sur une base de données de développement. Enfin, créez une migration pour le nouveau schéma et appliquez-la :
npx prisma migrate dev
Redémarrez l’application (npm run dev) et connectez-vous via Google. Une nouvelle ligne doit apparaître dans la table User, avec une ligne associée dans Account pour le lien Google. Pour examiner ces lignes, lancez npx prisma studio, le navigateur visuel de base de données fourni avec Prisma.
Affecter les publications à l’utilisateur connecté
Le formulaire d’exemple fourni dans le guide Prisma crée des articles avec un authorId codé de manière fixe. Désormais que les sessions existent, la page peut lire la session et utiliser le véritable identifiant utilisateur à la place. La page ci-dessous appelle auth(), affiche un message aux visiteurs anonymes, et transmet session.user.id à Prisma lors de la création de l’article. Elle révérifie ensuite la liste des articles et redirige vers celle-ci :
export default async function NewPost() {
const session = await auth();
async function createPost(formData: FormData) {
"use server";
if(!session?.user?.id){
return;
}
const title = formData.get("title") as string;
const content = formData.get("content") as string;
await prisma.post.create({
data: {
title,
content,
authorId: session.user.id,
},
});
revalidatePath("/posts");
redirect("/posts");
}
if(!session?.user){
return <div>You need to sign in to create a post</div>
}
...
}
Une amélioration est nécessaire avant que cela ne soit utilisé en production. L’action lit la valeur session depuis l’affichage de la page via une clôture. Une action serveur étant un point d’entrée public qui peut être invoqué directement, le schéma plus sûr consiste à appeler auth() à l’intérieur du corps de l’action et à vérifier le résultat là, ce qui fait que la vérification s’exécute à chaque soumission. Nous expliquons pourquoi les actions serveurs nécessitent une autorisation à l’intérieur de chaque corps de fonction. Il est également judicieux de valider title et content plutôt que de les convertir avec as string.
Conclusion
- Suivez les guides officiels de Prisma et d’Auth.js, mais corrigez l’import du client généré pour qu’il pointe vers
generated/prisma/clientet assurez-vous de la cohérence entresrc/appetapp/. - Gardez tous les secrets et chaînes de connexion dans un fichier d’environnement qui ne sera jamais commité.
- Omettez le
middleware.tsdécrit dans la documentation ; Next.js actuel utilise la convention du proxy, et les vérificationsauth()au niveau de la page suffisent ici. - L’ajout de l’adaptateur Prisma modifie la structure requise pour
User. Réinitialiser est acceptable pour une démonstration, mais les données existantes nécessitent une véritable migration. - Vérifiez la session à l’intérieur de chaque action serveur, et non seulement sur la page qui affiche le formulaire.
À partir de là, les prochaines étapes logiques consistent à permettre la connexion depuis des composants clients et à pointer DATABASE_URL vers une instance Postgres hébergée pour le déploiement.