From c7d6484eb80ea3ee74a53bad587aee05221bd4e1 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Thu, 3 Oct 2024 18:20:28 +0200 Subject: [PATCH] chore: WIP --- actions/auth/auth.ts | 25 +++++++--------- auth.config.ts | 69 ++++++++++++++++++++++++++++++++++++++++---- types/components.ts | 6 ++++ 3 files changed, 80 insertions(+), 20 deletions(-) diff --git a/actions/auth/auth.ts b/actions/auth/auth.ts index 19bbb5368b..658d711402 100644 --- a/actions/auth/auth.ts +++ b/actions/auth/auth.ts @@ -1,16 +1,12 @@ "use server"; -import { jwtDecode, JwtPayload } from "jwt-decode"; +import { jwtDecode } from "jwt-decode"; import { AuthError } from "next-auth"; import { z } from "zod"; import { signIn, signOut } from "@/auth.config"; import { parseStringify } from "@/lib"; -import { authFormSchema } from "@/types"; - -interface CustomJwtPayload extends JwtPayload { - user_id: string; -} +import { authFormSchema, CustomJwtPayload } from "@/types"; const formSchemaSignIn = authFormSchema("sign-in"); // const formSchemaSignUp = authFormSchema("sign-up"); @@ -93,15 +89,14 @@ export const getToken = async (formData: z.infer) => { const userId = decodedToken.user_id; // Verify if the response contains the expected data - if (data && data.data && data.data.attributes) { - return { - email: formData.email, - accessToken, - refreshToken, - userId, - // Add here other user fields we need in the session - }; - } + + return { + email: formData.email, + accessToken, + refreshToken, + userId, + // Add here other user fields we need in the session + }; } catch (error) { // eslint-disable-next-line no-console console.error("Error en trying to get token:", error); diff --git a/auth.config.ts b/auth.config.ts index e2d591c080..b5d36fc8b3 100644 --- a/auth.config.ts +++ b/auth.config.ts @@ -1,8 +1,55 @@ +import { jwtDecode } from "jwt-decode"; import NextAuth, { type NextAuthConfig } from "next-auth"; import Credentials from "next-auth/providers/credentials"; import { z } from "zod"; import { getToken } from "./actions/auth"; +import { CustomJwtPayload } from "./types"; + +const refreshAccessToken = async (token: CustomJwtPayload) => { + const keyServer = process.env.API_BASE_URL; + const url = new URL(`${keyServer}/tokens/refresh`); + + const bodyData = { + data: { + type: "TokenRefresh", + attributes: { + refresh: token.refreshToken, + }, + }, + }; + + try { + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/vnd.api+json", + Accept: "application/vnd.api+json", + }, + body: JSON.stringify(bodyData), + }); + // console.log("response", response); + const newTokens = await response.json(); + + if (!response.ok) { + // TODO: handle error + throw new Error(`HTTP error! status: ${response.status}`); + } + + return { + ...token, + accessToken: newTokens.data.attributes.access, + refreshToken: newTokens.data.attributes.refresh, + }; + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error refreshing access token:", error); + return { + ...token, + error: "RefreshAccessTokenError", + }; + } +}; export const authConfig = { session: { @@ -57,10 +104,13 @@ export const authConfig = { }, jwt: async ({ token, user, account }) => { - // console.log(`In jwt callback - Token is ${JSON.stringify(token)}`); + if (token?.accessToken) { + const decodedToken = jwtDecode(token.accessToken); + console.log("decodedToken", decodedToken); + + token.accessTokenExpires = decodedToken?.exp * 1000; + } if (user && account) { - // console.log(`In jwt callback - User is ${JSON.stringify(user)}`); - // console.log(`In jwt callback - Account is ${JSON.stringify(account)}`); // token.data = user; return { ...token, @@ -69,11 +119,20 @@ export const authConfig = { user, }; } - return token; + + console.log( + "Access token expires", + token.accessTokenExpires, + new Date(Number(token.accessTokenExpires)), + ); + + if (Date.now() < token.accessTokenExpires) return token; + + // Access token is expired, we need to refresh it + return refreshAccessToken(token); }, session: async ({ session, token }) => { - console.log(`In session callback - Token is ${JSON.stringify(token)}`); // session.user = token.data as any; if (token) { session.accessToken = token.accessToken; diff --git a/types/components.ts b/types/components.ts index 28ffbe7355..9ad3507108 100644 --- a/types/components.ts +++ b/types/components.ts @@ -1,3 +1,4 @@ +import { JwtPayload } from "jwt-decode"; import { SVGProps } from "react"; export type IconSvgProps = SVGProps & { @@ -29,6 +30,11 @@ export type NextUIColors = export interface SearchParamsProps { [key: string]: string | string[] | undefined; } + +export interface CustomJwtPayload extends JwtPayload { + user_id: string; + tenant_id: string; +} export interface ProviderProps { id: string; type: "providers";