Retour • 27/08/2024
Comment configurer NextAuth Password avec une base de données (Next App Directory)
Écris par Melvyn Malherbe le 27/08/2024
Si vous allez à la section NextAuth Credentials, vous verrez que la fonctionnalité est "découragée" afin de limiter son utilisation.
De plus, vous devrez configurer la stratégie JWT
pour la faire fonctionner.
Mais... comment l'utiliser avec notre base de données ? Que faire si nous ne voulons pas passer à JWT
et que nous voulons de la flexibilité ?
Je vais vous aider à le configurer avec votre base de données dans cet article.
Ce tutoriel vous aide à configurer NextAuth avec un mot de passe et la structure du répertoire NextJS App. Si vous recherchez la version du répertoire de pages, consultez mon post précédent.
Configuration
Pour configurer les Credentials de NextAuth, nous allons suivre les étapes de base ! Dans votre configuration NextAuth, ajoutez le Credentials Provider :
import CredentialsProvider from 'next-auth/providers/credentials';
export const { handlers, auth: baseAuth } = NextAuth((request) => ({
adapter: PrismaAdapter(prisma),
providers: [
CredentialsProvider({
name: 'Credentials',
credentials: {
email: { label: 'Email', type: 'text', placeholder: 'votre email' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials, req) {
// votre logique avec votre base de données ici
}
});
],
session: {
strategy: "database",
},
secret: env.NEXTAUTH_SECRET,
}));
Ensuite, vous pouvez utiliser la méthode handlers
dans le fichier app/api/auth/[...nextauth]/route.ts
:
import { handlers } from '@/lib/auth/auth';
export const { GET, POST } = handlers;
Fonction d'autorisation
Pour créer notre stratégie par mot de passe, nous devrons ajouter une fonction events
à notre configuration.
Vous devrez ajouter la fonction signIn
comme ceci :
export const { handlers, auth: baseAuth } = NextAuth((request) => ({
events: {
async signIn({ user }) {
// votre logique ici
},
},
});
Dans cette fonction, nous commencerons par savoir si la méthode signIn
a été appelée avec les options credentials
, car nous ne gérerons aucun autre cas.
export const { handlers, auth: baseAuth } = NextAuth((request) => ({
events: {
async signIn({ user }) {
if (!request) {
return;
}
if (request.method !== "POST") {
return;
}
const currentUrl = request.url;
// Nous vérifions si l'utilisateur se connecte avec des credentials
if (!currentUrl.includes("credentials")) {
return;
}
if (!currentUrl.includes("callback")) {
return;
}
},
},
});
Nous vérifions s'il n'y a pas de callback OU s'il n'y a pas de credentials
dans la query OU si la méthode n'est pas POST
, nous retournons true
pour laisser NextAuth gérer l'authentification.
Et maintenant, nous devrons faire exactement comme NextAuth le fait avec d'autres méthodes pour gérer l'authentification avec un mot de passe.
D'abord, au début de mon fichier, j'avais ceci :
const tokenName =
env.NODE_ENV === 'development'
? 'next-auth.session-token'
: '__Secure-next-auth.session-token';
Le tokenName
dans le Cookie
a un nom différent si nous sommes en développement ou en production. Donc, nous devrons faire la même chose ici.
export const { handlers, auth: baseAuth } = NextAuth((request) => ({
callbacks: {
async signIn({ user }) {
if (!request) {
return;
}
if (request.method !== "POST") {
return;
}
const currentUrl = request.url;
// Nous vérifions si l'utilisateur se connecte avec des credentials
if (!currentUrl.includes("credentials")) {
return;
}
if (!currentUrl.includes("callback")) {
return;
}
// Nous créons une session
const uuid = nanoid();
const expireAt = addDays(new Date(), 14);
// J'utilise prisma pour l'exemple
await prisma.session.create({
data: {
sessionToken: uuid,
userId: user.id ?? "",
expires: expireAt,
},
});
const cookieList = cookies();
const AUTH_COOKIE_NAME =
env.NODE_ENV === "development"
? "authjs.session-token"
: "__Secure-authjs.session-token";
// Créez et définissez un cookie avec exactement la même valeur
cookieList.set(AUTH_COOKIE_NAME, uuid, {
expires: expireAt,
path: "/",
sameSite: "lax",
httpOnly: true,
secure: env.NODE_ENV === "production",
});
return;
},
},
});
Dans ce code, je génère un nanoid
qui agira comme un token. J'utilise la bibliothèque nanoid
pour cela.
Ensuite, je génère une date expireAt
qui représente 7 jours après aujourd'hui, et je crée une session dans
prisma en utilisant le sessionToken
comme uuid
, le userId
, et la date expireAt
.
Ensuite, je crée un cookie avec la bibliothèque Cookie
, et je définis le tokenName
comme le uuid
, et je définis la date expireAt
.
Ensuite, je dois ajouter un Cookie
à l'objet res
, donc j'utilise la bibliothèque Cookie
pour cela. N'oubliez pas d'ajouter l'option secure
à true
si vous êtes en production.
Je définis
enfin le cookie avec le tokenName
comme le uuid
, la date expireAt
, l'option secure
, l'option sameSite
, et l'option path
.
Override jwt
Si vous faites tout ce qui précède, cela ne fonctionnera pas. NextAuth supprimera le token car il ne le reconnaît pas.
Pour résoudre ce problème, nous désactiverons la méthode jwt
:
export const { handlers, auth: baseAuth } = NextAuth((request) => ({
// ...
jwt: {
encode() {
return "";
},
async decode() {
return null;
},
};
}));
Avec ce code, NextAuth connectera correctement l'utilisateur avec le cookie créé ensemble.
Conclusion
J'espère que cet article vous aidera à faire fonctionner votre authentification avec NextJS 14.