diff --git a/lib/build/nextjs.d.ts b/lib/build/nextjs.d.ts index 7b06b2936..0de2b5448 100644 --- a/lib/build/nextjs.d.ts +++ b/lib/build/nextjs.d.ts @@ -1,5 +1,6 @@ // @ts-nocheck import { CollectingResponse, PreParsedRequest } from "./framework/custom"; +import { SSRSessionContextType } from "./types"; import { SessionContainer, VerifySessionOptions } from "./recipe/session"; declare type PartialNextRequest = { method: string; @@ -37,6 +38,7 @@ export default class NextJS { hasToken: boolean; hasInvalidClaims: boolean; }>; + static getInitialSessionAuthContext(session: SessionContainer | undefined): Promise; static withSession( req: NextRequest, handler: (error: Error | undefined, session: SessionContainer | undefined) => Promise, @@ -51,6 +53,7 @@ export default class NextJS { export declare let superTokensNextWrapper: typeof NextJS.superTokensNextWrapper; export declare let getAppDirRequestHandler: typeof NextJS.getAppDirRequestHandler; export declare let getSSRSession: typeof NextJS.getSSRSession; +export declare let getInitialSessionAuthContext: typeof NextJS.getInitialSessionAuthContext; export declare let withSession: typeof NextJS.withSession; export declare let withPreParsedRequestResponse: typeof NextJS.withPreParsedRequestResponse; export {}; diff --git a/lib/build/nextjs.js b/lib/build/nextjs.js index 8fcef6c53..e89b292fd 100644 --- a/lib/build/nextjs.js +++ b/lib/build/nextjs.js @@ -16,7 +16,7 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.withPreParsedRequestResponse = exports.withSession = exports.getSSRSession = exports.getAppDirRequestHandler = exports.superTokensNextWrapper = void 0; +exports.withPreParsedRequestResponse = exports.withSession = exports.getInitialSessionAuthContext = exports.getSSRSession = exports.getAppDirRequestHandler = exports.superTokensNextWrapper = void 0; /* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. * * This software is licensed under the Apache License, Version 2.0 (the @@ -178,6 +178,21 @@ class NextJS { result = __rest(_a, ["baseResponse", "nextResponse"]); return result; } + static async getInitialSessionAuthContext(session) { + const initialContext = { + isContextFromSSR: true, + loading: false, + doesSessionExist: false, + accessTokenPayload: {}, + userId: "", + }; + if (session) { + initialContext.doesSessionExist = true; + initialContext.accessTokenPayload = await session.getAccessTokenPayload(); + initialContext.userId = await session.getUserId(); + } + return initialContext; + } static async withSession(req, handler, options, userContext) { try { const query = Object.fromEntries(new URL(req.url).searchParams.entries()); @@ -322,5 +337,6 @@ exports.default = NextJS; exports.superTokensNextWrapper = NextJS.superTokensNextWrapper; exports.getAppDirRequestHandler = NextJS.getAppDirRequestHandler; exports.getSSRSession = NextJS.getSSRSession; +exports.getInitialSessionAuthContext = NextJS.getInitialSessionAuthContext; exports.withSession = NextJS.withSession; exports.withPreParsedRequestResponse = NextJS.withPreParsedRequestResponse; diff --git a/lib/build/types.d.ts b/lib/build/types.d.ts index 6b3e0e34b..a3170a09d 100644 --- a/lib/build/types.d.ts +++ b/lib/build/types.d.ts @@ -86,3 +86,10 @@ export declare type User = { })[]; toJson: () => any; }; +export declare type SSRSessionContextType = { + isContextFromSSR: true; + loading: false; + doesSessionExist: boolean; + accessTokenPayload: any; + userId?: string; +}; diff --git a/lib/ts/nextjs.ts b/lib/ts/nextjs.ts index f76a3f3e7..ff05e2318 100644 --- a/lib/ts/nextjs.ts +++ b/lib/ts/nextjs.ts @@ -20,7 +20,7 @@ import { middleware, errorHandler as customErrorHandler, } from "./framework/custom"; -import { HTTPMethod } from "./types"; +import { HTTPMethod, SSRSessionContextType } from "./types"; import Session, { SessionContainer, VerifySessionOptions } from "./recipe/session"; import SessionRecipe from "./recipe/session/recipe"; import { getToken } from "./recipe/session/cookieAndHeaders"; @@ -230,6 +230,24 @@ export default class NextJS { return result; } + static async getInitialSessionAuthContext(session: SessionContainer | undefined): Promise { + const initialContext: SSRSessionContextType = { + isContextFromSSR: true, + loading: false, + doesSessionExist: false, + accessTokenPayload: {}, + userId: "", + }; + + if (session) { + initialContext.doesSessionExist = true; + initialContext.accessTokenPayload = await session.getAccessTokenPayload(); + initialContext.userId = await session.getUserId(); + } + + return initialContext; + } + static async withSession( req: NextRequest, handler: (error: Error | undefined, session: SessionContainer | undefined) => Promise, @@ -405,5 +423,6 @@ export default class NextJS { export let superTokensNextWrapper = NextJS.superTokensNextWrapper; export let getAppDirRequestHandler = NextJS.getAppDirRequestHandler; export let getSSRSession = NextJS.getSSRSession; +export let getInitialSessionAuthContext = NextJS.getInitialSessionAuthContext; export let withSession = NextJS.withSession; export let withPreParsedRequestResponse = NextJS.withPreParsedRequestResponse; diff --git a/lib/ts/types.ts b/lib/ts/types.ts index 4fc906b82..ee9655f3f 100644 --- a/lib/ts/types.ts +++ b/lib/ts/types.ts @@ -113,3 +113,11 @@ export type User = { // the recipeUserId can be converted to string from the RecipeUserId object type. toJson: () => any; }; + +export type SSRSessionContextType = { + isContextFromSSR: true; + loading: false; + doesSessionExist: boolean; + accessTokenPayload: any; + userId: string; +}; diff --git a/test/nextjs.test.js b/test/nextjs.test.js index 2f0fd38ee..e434f629e 100644 --- a/test/nextjs.test.js +++ b/test/nextjs.test.js @@ -26,6 +26,7 @@ const { superTokensNextWrapper, withSession, getSSRSession, + getInitialSessionAuthContext, getAppDirRequestHandler, withPreParsedRequestResponse, } = require("../lib/build/nextjs"); @@ -774,6 +775,38 @@ describe(`Next.js App Router: ${printPath("[test/nextjs.test.js]")}`, function ( assert.equal(sessionContainer.hasToken, true); }); + it("getInitialSessionAuthContext", async function () { + const tokens = await getValidTokensAfterSignup({ tokenTransferMethod: "header" }); + + const authenticatedRequest = new NextRequest("http://localhost:3000/api/get-user", { + headers: { + Authorization: `Bearer ${tokens.access}`, + }, + }); + + let sessionContainer = await getSSRSession(authenticatedRequest.cookies.getAll(), authenticatedRequest.headers); + + let initialSessionAuthContext = await getInitialSessionAuthContext(sessionContainer.session); + + assert.equal(initialSessionAuthContext.loading, false); + assert.equal(initialSessionAuthContext.isContextFromSSR, true); + assert.equal(initialSessionAuthContext.doesSessionExist, true); + assert.equal(initialSessionAuthContext.userId, process.env.user); + assert.notEqual(initialSessionAuthContext.accessTokenPayload, {}); + + const unAuthenticatedRequest = new NextRequest("http://localhost:3000/api/get-user"); + + sessionContainer = await getSSRSession(unAuthenticatedRequest.cookies.getAll(), unAuthenticatedRequest.headers); + + initialSessionAuthContext = await getInitialSessionAuthContext(sessionContainer.session); + + assert.equal(initialSessionAuthContext.loading, false); + assert.equal(initialSessionAuthContext.isContextFromSSR, true); + assert.equal(initialSessionAuthContext.doesSessionExist, false); + assert.equal(initialSessionAuthContext.userId, ""); + assert.deepEqual(initialSessionAuthContext.accessTokenPayload, {}); + }); + it("withSession", async function () { const tokens = await getValidTokensAfterSignup({ tokenTransferMethod: "header" });