I'm developing the frontend of an application with NextJS 14. I have configured a CredentialsProvider with NextAuth, user provides email and password and it is sent to the Backend (SpringBoot) to authenticate them and the Backend sends a JWT if the authentication is successful.
I store the access token in a cookie to use it when I make a request to the backend (using an Authentication header) but I'm not sure if there's a better approach. And in some pages it is causing problems to retrieve the cookie.
Can I store it in the session? If so, how?
This is my credentials provider:
import type { NextAuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { cookies } from "next/headers";
const loginPath: string = process.env.NEXT_PUBLIC_LOGIN_PATH!;
const parsePayload = (token: string) => {
try {
return JSON.parse(atob(token.split('.')[1]));
} catch (e) {
return null;
}
};
export const authOptions: NextAuthOptions = {
session: {
strategy: "jwt",
},
providers: [
CredentialsProvider({
name: "credentials",
credentials: {
username: {label: "Username", type: "text"},
password: {label: "Password", type: "password"},
},
async authorize (credentials) {
const {username, password} = credentials as {
username: string;
password: string;
};
const formData = new URLSearchParams();
formData.append("email", encodeURIComponent(username));
formData.append("password", encodeURIComponent(password));
const res = await fetch (loginPath, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: formData.toString(),
});
const receivedToken = await res.json();
if (res.ok && receivedToken) {
const user = receivedToken;
const parsed = parsePayload(receivedToken.access_token);
user.name = parsed.name;
cookies().set({
name: "gat",
value: receivedToken.access_token,
httpOnly: true});
cookies().set({
name: "grt",
value: receivedToken.refresh_token,
httpOnly: true});
return user;
} else {
return null;
}
},
}),
],
callbacks: {
jwt: async ({token, user}: {token: any, user: any}) => {
if (user) token = user as unknown as {[key: string]: any};
return token;
},
session: async ({ session, token }: {session: any, token: any}) => {
session.user = { ...token }
return session;
},
},
pages: {
signIn: "/login",
},
};
The problem is that I have access to that "gat" cookie only from server components using:
import { cookies } from 'next/headers'
console.log("GAT: " + cookies().get("gat")?.value);
And if I need to make a call from a client component I need to pass that value to the client component as a parameter, which I find pretty awful...
first create file for ActionServer:
ServerActions.ts
"use server";
export async function setToken(token: string) {
cookies().set("token", tok);
}
export async function getToken() {
const token = cookies().get("token");
return token?.value;
}
you can get server side:
page.ts:
const token = await getToken();
and for client :
const test = async = ()=> {
const token = await getToken();
// you do anyting you want
// you can use this in useEffect !!
}