web:framework:nextjs:nextauth

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Prochaine révision
Révision précédente
web:framework:nextjs:nextauth [2025/03/18 13:57] – créée jcheronweb:framework:nextjs:nextauth [2025/08/12 02:35] (Version actuelle) – modification externe 127.0.0.1
Ligne 7: Ligne 7:
 npm install next-auth@beta @types/next-auth npm install next-auth@beta @types/next-auth
 </sxh> </sxh>
 +
 +===== Configuration =====
 +
 +<sxh typescript;title:src/auth.ts>
 +import NextAuth from "next-auth";
 +import CredentialsProvider from "next-auth/providers/credentials";
 +import HttpService from "@/services/HttpService";
 +import API_URLS from "@/constants/ApiUrls";
 +import { decodeJwt } from "jose";
 +
 +interface AuthToken {
 +    accessToken: string;
 +    refreshToken: string;
 +    user: any;
 +}
 +
 +async function refreshAccessToken(token: AuthToken) {
 +    try {
 +        const refreshedToken = await HttpService.post(API_URLS.refreshToken, {
 +            refreshToken: token.refreshToken,
 +        });
 +
 +        if (!refreshedToken || !refreshedToken.accessToken) {
 +            throw new Error("Refresh token failed");
 +        }
 +
 +        return {
 +            ...token,
 +            accessToken: refreshedToken.accessToken,
 +            accessTokenExpires: Date.now() + refreshedToken.expiresIn * 1000,
 +            refreshToken: refreshedToken.refreshToken ?? token.refreshToken,
 +        };
 +    } catch (error) {
 +        console.error("Erreur lors du rafraîchissement du token", error);
 +        return { ...token, error: "RefreshAccessTokenError" };
 +    }
 +}
 +
 +// @ts-ignore
 +export const authConfig = {
 +    pages: {
 +        signIn: '/login',
 +        signOut: "/logout",
 +    },
 +    providers: [
 +        CredentialsProvider({
 +            id: "credentials",
 +            name: "Credentials",
 +            credentials: {
 +                username: { label: "Login", type: "text" },
 +                password: { label: "Password", type: "password" },
 +            },
 +            async authorize(credentials) {
 +                const resp = await HttpService.post(API_URLS.authLogin, {
 +                    username: credentials.username,
 +                    password: credentials.password,
 +                });
 +
 +                if (resp.ok) {
 +                    throw new Error("Invalid credentials");
 +                }
 +                const token=resp.data;
 +                const user = decodeJwt(token.accessToken);
 +
 +                return {
 +                    id: user.sub,
 +                    name: user.name,
 +                    email: user.email,
 +                    role: user.role,
 +                    accessToken: token.accessToken,
 +                    //refreshToken: token.refreshToken,
 +                    accessTokenExpires: Date.now() + token.expiresIn * 1000,
 +                };
 +            },
 +        }),
 +    ],
 +    callbacks: {
 +        async jwt({ token, user }) {
 +            if (user) {
 +                return {
 +                    accessToken: user.accessToken,
 +                    //refreshToken: user.refreshToken,
 +                    accessTokenExpires: Date.now() + 1000 * 60 * 60, // 1h
 +                    user: {
 +                        id: user.id,
 +                        name: user.name,
 +                        email: user.email,
 +                        role: user.role
 +                    },
 +                };
 +            }
 +
 +            if (Date.now() < token.accessTokenExpires) {
 +                return token;
 +            }
 +
 +            return refreshAccessToken(token);
 +        },
 +        async session({ session, token }) {
 +            console.log("session in session method", session);
 +            console.log("token in session method", token);
 +            return {
 +                ...session,
 +                user: {
 +                    ...session.user,
 +                    id: token.user.id,
 +                    name: token.user.name,
 +                    email: token.user.email,
 +                    accessToken: token.accessToken,
 +                    //refreshToken: token.refreshToken,
 +                },
 +            };
 +        },
 +    },
 +    session: {
 +        strategy: 'jwt',
 +    },
 +    secret: process.env.NEXTAUTH_SECRET as string,
 +} satisfies NextAuthConfig;
 +
 +//@ts-ignore
 +export const {handlers, auth, signIn, signOut} = NextAuth(authConfig);
 +
 +</sxh>
 +
 +
 +
 +===== Route api =====
 +Toutes les requêtes NextAuth passeront par cette route : ''src/app/api/auth/[...nextauth]/route.tsx''
 +
 +<sxh typescript>
 +import {handlers} from "@/auth";
 +export const {GET, POST} = handlers;
 +</sxh>
 +
 +
 +===== Lib =====
 +Fichier utilitaire pour simplifier connexion et déconnexion dans ''src/lib/actions.ts'':
 +
 +<sxh typescript>
 +'use server';
 +import {signIn, signOut} from "@/auth";
 +
 +
 +interface LoginFormValues {
 +    username: string;
 +    password: string;
 +    rememberMe?: boolean;
 +};
 +export const submitLogin = async (formData: LoginFormValues): Promise<any> => {
 +    await signIn('credentials', {...formData, redirectTo: '/', redirect: true});
 +};
 +
 +export const submitLogout = async () => {
 +    await signOut({redirect: true, redirectTo: '/logout'});
 +};
 +</sxh>
 +
 +===== LoginForm =====
 +Exemple de composant pour le login :
 +<sxh typescript>
 +'use client';
 +import {Button, Checkbox, Form, Input} from "antd";
 +import {submitLogin} from "@/lib/actions";
 +
 +
 +export default function SignInComponent(){
 +    const onFinish = async (values: any) => {
 +        await submitLogin(values);
 +    };
 +
 +    const onFinishFailed = (errorInfo: any) => {
 +        console.log('Failed:', errorInfo);
 +    };
 +    return
 +     <div>
 +         <Form
 +             name="basic"
 +             labelCol={{ span: 8 }}
 +             wrapperCol={{ span: 16 }}
 +             style={{ maxWidth: 600 }}
 +             initialValues={{ remember: true }}
 +             onFinish={onFinish}
 +             onFinishFailed={onFinishFailed}
 +             autoComplete="off"
 +         >
 +             <Form.Item
 +                 label="Username"
 +                 name="username"
 +                 rules={[{ required: true, message: 'Please input your username!' }]}
 +             >
 +                 <Input />
 +             </Form.Item>
 +
 +             <Form.Item
 +                 label="Password"
 +                 name="password"
 +                 rules={[{ required: true, message: 'Please input your password!' }]}
 +             >
 +                 <Input.Password />
 +             </Form.Item>
 +
 +             <Form.Item name="remember" valuePropName="checked" label={null}>
 +                 <Checkbox>Remember me</Checkbox>
 +             </Form.Item>
 +
 +             <Form.Item label={null}>
 +                 <Button type="primary" htmlType="submit">
 +                     Submit
 +                 </Button>
 +             </Form.Item>
 +         </Form>
 +     </div>
 +}
 +</sxh>
 +
 +===== Configuration =====
 +
 +Dans le fichier ''.env'' ou ''.env.local'', définir la variable ''NEXTAUTH_URL'':
 +
 +<sxh env>
 +NEXTAUTH_URL=http://127.0.0.1:3000
 +</sxh>
 +
 +
 +Génération du secret pour encodage/décodage JWT :
 +
 +<sxh bash>
 +npx auth secret
 +</sxh>
 +
 +Le **secret** est généré et inséré dans le fichier ''.env.local''.
 +===== Usage =====
 +Accès à la session nextAuth :
 +
 +==== Côté serveur ====
 +
 +<sxh ts;gutter:false>
 +import {auth} from "@/auth";
 +
 +const session= await auth();
 +console.log(session.user); //user connecté
 +</sxh>
 +
 +==== Côté client ====
 +
 +<sxh ts;gutter:false>
 +'use client';
 +import {useSession} from "next-auth/react";
 +
 +const userData=useSession();
 +console.log(userData.data?.user); //user connecté
 +</sxh>
 +
  
  
  • web/framework/nextjs/nextauth.1742302664.txt.gz
  • Dernière modification : il y a 8 semaines
  • (modification externe)