From 41a2dbe6a053348015d0a9786dd8c0e1e74396f6 Mon Sep 17 00:00:00 2001 From: Paul Asjes Date: Thu, 26 Sep 2024 07:31:27 -0400 Subject: [PATCH] Add getSession (#91) * Add getSession * Update wording * Fixed bug where getSession wouldn't return a session after a refresh --- README.md | 24 ++++++++++++++++++++++++ src/index.ts | 3 ++- src/session.ts | 31 ++++++++++++++++++++++++++++--- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0501cc6..b6e3bdf 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,30 @@ In the above example the `/admin` page will require a user to be signed in, wher `unauthenticatedPaths` uses the same glob logic as the [Next.js matcher](https://nextjs.org/docs/pages/building-your-application/routing/middleware#matcher). +### Retrieve session in middleware + +Sometimes it's useful to check the user session if you want to compose custom middleware. The `getSession` helper method will retrieve the session from the cookie and verify the access token. + +```ts +import { authkitMiddleware, getSession } from '@workos-inc/authkit-nextjs'; +import { NextRequest } from 'next/server'; + +export default async function middleware(request: NextRequest) { + // authkitMiddleware will handle refreshing the session if the access token has expired + const response = await authkitMiddleware()(request); + + // If session is undefined, the user is not authenticated + const session = await getSession(response); + + // ...add additional middleware logic here + + return response; +} + +// Match against pages that require auth +export const config = { matcher: ['/', '/account/:path*'] }; +``` + ### Signing out Use the `signOut` method to sign out the current logged in user and redirect to your app's homepage. The homepage redirect is set in your WorkOS dashboard settings under "Redirect". diff --git a/src/index.ts b/src/index.ts index b39f905..d2e5306 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import { handleAuth } from './authkit-callback-route.js'; import { authkitMiddleware } from './middleware.js'; -import { getUser, refreshSession } from './session.js'; +import { getUser, refreshSession, getSession } from './session.js'; import { getSignInUrl, getSignUpUrl, signOut } from './auth.js'; import { Impersonation } from './impersonation.js'; import { AuthKitProvider } from './provider.js'; @@ -9,6 +9,7 @@ export { handleAuth, // authkitMiddleware, + getSession, // getSignInUrl, getSignUpUrl, diff --git a/src/session.ts b/src/session.ts index 1268ab7..347577c 100644 --- a/src/session.ts +++ b/src/session.ts @@ -239,8 +239,8 @@ async function verifyAccessToken(accessToken: string) { } } -async function getSessionFromCookie() { - const cookie = cookies().get(cookieName); +async function getSessionFromCookie(response?: NextResponse) { + const cookie = response ? response.cookies.get(cookieName) : cookies().get(cookieName); if (cookie) { return unsealData(cookie.value, { password: WORKOS_COOKIE_PASSWORD, @@ -248,6 +248,31 @@ async function getSessionFromCookie() { } } +/** + * Retrieves the session from the cookie. Meant for use in the middleware, for client side use `getUser` instead. + * + * @returns Session | undefined + */ +async function getSession(response?: NextResponse) { + const session = await getSessionFromCookie(response); + + if (!session) return; + + if (await verifyAccessToken(session.accessToken)) { + const { sid: sessionId, org_id: organizationId, role, permissions } = decodeJwt(session.accessToken); + + return { + sessionId, + user: session.user, + organizationId, + role, + permissions, + impersonator: session.impersonator, + accessToken: session.accessToken, + }; + } +} + async function getSessionFromHeader(caller: string): Promise { const hasMiddleware = Boolean(headers().get(middlewareHeaderName)); @@ -269,4 +294,4 @@ function getReturnPathname(url: string): string { return `${newUrl.pathname}${newUrl.searchParams.size > 0 ? '?' + newUrl.searchParams.toString() : ''}`; } -export { encryptSession, getUser, refreshSession, terminateSession, updateSession }; +export { encryptSession, getUser, refreshSession, terminateSession, updateSession, getSession };