From 726a8ed3d9e399ea1b4d01425c6a2ae65d7d159a Mon Sep 17 00:00:00 2001 From: guabu <135956181+guabu@users.noreply.github.com> Date: Tue, 3 Dec 2024 08:25:56 +0100 Subject: [PATCH] 4.0.0-beta.9 (#1827) --- README.md | 32 ++++++++++++++++++++++++- package.json | 2 +- src/client/hooks/use-user.ts | 9 +++++++ src/client/index.ts | 1 + src/client/providers/auth0-provider.tsx | 26 ++++++++++++++++++++ src/server/auth-client.test.ts | 5 ++++ src/server/auth-client.ts | 5 +++- src/server/client.ts | 8 +++---- 8 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 src/client/providers/auth0-provider.tsx diff --git a/README.md b/README.md index 493a1f82..5fcca121 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ### 1. Install the SDK ```shell -npm i @auth0/nextjs-auth0@4.0.0-beta.8 +npm i @auth0/nextjs-auth0@4.0.0-beta.9 ``` ### 2. Add the environment variables @@ -322,6 +322,36 @@ export default async function handler( } ``` +## `` + +### Passing an initial user from the server + +You can wrap your components in an `` and pass an initial user object to make it available to your components using the `useUser()` hook. For example: + +```tsx +import { Auth0Provider } from "@auth0/nextjs-auth0" + +import { auth0 } from "@/lib/auth0" + +export default async function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode +}>) { + const session = await auth0.getSession() + + return ( + + + {children} + + + ) +} +``` + +The loaded user will then be used as a fallback in `useUser()` hook. + ## Hooks The SDK exposes hooks to enable you to provide custom logic that would be run at certain lifecycle events. diff --git a/package.json b/package.json index 6c810444..cccf2eb3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@auth0/nextjs-auth0", - "version": "4.0.0-beta.8", + "version": "4.0.0-beta.9", "description": "Auth0 Next.js SDK", "main": "dist/index.js", "scripts": { diff --git a/src/client/hooks/use-user.ts b/src/client/hooks/use-user.ts index d9ed8a9b..681c4461 100644 --- a/src/client/hooks/use-user.ts +++ b/src/client/hooks/use-user.ts @@ -17,6 +17,15 @@ export function useUser() { }) ) + // if we have the user loaded via the provider, return it + if (data) { + return { + user: data, + isLoading: false, + error: null, + } + } + if (error) { return { user: null, diff --git a/src/client/index.ts b/src/client/index.ts index f6baabcc..1804b203 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -1,2 +1,3 @@ export { useUser } from "./hooks/use-user" export { getAccessToken } from "./helpers/get-access-token" +export { Auth0Provider } from "./providers/auth0-provider" diff --git a/src/client/providers/auth0-provider.tsx b/src/client/providers/auth0-provider.tsx new file mode 100644 index 00000000..8195cb0c --- /dev/null +++ b/src/client/providers/auth0-provider.tsx @@ -0,0 +1,26 @@ +"use client" + +import React from "react" +import { SWRConfig } from "swr" + +import { User } from "../../types" + +export function Auth0Provider({ + user, + children, +}: { + user?: User + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/src/server/auth-client.test.ts b/src/server/auth-client.test.ts index 256674fa..614a4d9b 100644 --- a/src/server/auth-client.test.ts +++ b/src/server/auth-client.test.ts @@ -1337,6 +1337,11 @@ describe("Authentication Client", async () => { // query parameters expect(logoutUrl.searchParams.get("client_id")).toEqual(DEFAULT.clientId) expect(logoutUrl.searchParams.get("returnTo")).toEqual(DEFAULT.appBaseUrl) + + // session cookie is cleared + const cookie = response.cookies.get("__session") + expect(cookie?.value).toEqual("") + expect(cookie?.expires).toEqual(new Date("1970-01-01T00:00:00.000Z")) }) it("should return an error if the discovery endpoint could not be fetched", async () => { diff --git a/src/server/auth-client.ts b/src/server/auth-client.ts index d8414665..f298e8c8 100644 --- a/src/server/auth-client.ts +++ b/src/server/auth-client.ts @@ -287,7 +287,10 @@ export class AuthClient { const url = new URL("/v2/logout", this.issuer) url.searchParams.set("returnTo", returnTo) url.searchParams.set("client_id", this.clientMetadata.client_id) - return NextResponse.redirect(url) + + const res = NextResponse.redirect(url) + await this.sessionStore.delete(req.cookies, res.cookies) + return res } const url = new URL(authorizationServerMetadata.end_session_endpoint) diff --git a/src/server/client.ts b/src/server/client.ts index 3617ed0b..e5b9c529 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -180,7 +180,7 @@ export class Auth0Client { * * This method can be used in Server Components, Server Actions, Route Handlers, and middleware in the **App Router**. */ - async getAccessToken(): Promise<{ token: string; expiresAt: number } | null> + async getAccessToken(): Promise<{ token: string; expiresAt: number }> /** * getAccessToken returns the access token. @@ -189,14 +189,14 @@ export class Auth0Client { */ async getAccessToken( req: PagesRouterRequest - ): Promise<{ token: string; expiresAt: number } | null> + ): Promise<{ token: string; expiresAt: number }> /** * getAccessToken returns the access token. */ async getAccessToken( req?: PagesRouterRequest - ): Promise<{ token: string; expiresAt: number } | null> { + ): Promise<{ token: string; expiresAt: number }> { let session: SessionData | null = null if (req) { @@ -212,7 +212,7 @@ export class Auth0Client { ) } - // if access token has expired, return null + // if access token has expired, throw an error if (session.tokenSet.expiresAt <= Date.now() / 1000) { if (!session.tokenSet.refreshToken) { throw new AccessTokenError(