Skip to content

Conversation

bcbogdan
Copy link
Contributor

@bcbogdan bcbogdan commented Feb 4, 2025

Summary of change

The following PR improves SSR support in Next.js applications.
To get the session data in the context of server side rendering you now have to call getSSRSession either inside a Server Component, or in getServerSideProps (for older next applications).
There's two parts to this change:

Fetching the session during SSR

The logic for this is kept in the ssr.ts file. The function reads the active tokens and has 3 possible outcomes:

  • redirect to the login page if there was an issue (unable to read the tokens, token payload was invalid)
  • redirect to the refresh api if the tokens have expired or if the front token payload is different from the access token payload
  • return the session value

Refreshing a session

The getSSRSession function redirects to a refresh endpoint that we do not expose from our existing API.
Hence, this change adds logic inside the next.js middleware to handle such a request. The custom middleware calls the backend API using a fetch and updates the response with the new tokens.

This part is now kept mostly in the middleware.ts file, in the react library. It's there just to make it easy to review during this stage. It should be moved in the node SDK package as a separate, Nextjs specific API.

Test Plan

(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Bonus points for screenshots and videos!)

Documentation changes

(If relevant, please create a PR in our docs repo, or create a checklist here highlighting the necessary changes)

Checklist for important updates

  • Changelog has been updated
  • frontendDriverInterfaceSupported.json file has been updated (if needed)
  • Changes to the version if needed
    • In package.json
    • In package-lock.json
    • In lib/ts/version.ts
  • Had run npm run build-pretty
  • Had installed and ran the pre-commit hook
  • Issue this PR against the latest non released version branch.
    • To know which one it is, run find the latest released tag (git tag) in the format vX.Y.Z, and then find the latest branch (git branch --all) whose X.Y is greater than the latest released tag.
    • If no such branch exists, then create one from the latest released branch.
  • If added a new recipe interface, then make sure that the implementation of it uses NON arrow functions only (like someFunc: function () {..}).
  • If I added a new recipe, I also added the recipe entry point into the size-limit section of package.json with the size limit set to the current size rounded up.
  • If I added a new recipe, I also added the recipe entry point into the rollup.config.mjs
  • If I added a new login method, I modified the list in lib/ts/types.ts
  • If I added a factor id, I modified the list in lib/ts/recipe/multifactorauth/types.ts

Remaining TODOs for this PR

  • Item1
  • Item2

@github-actions
Copy link
Contributor

github-actions bot commented Feb 12, 2025

size-limit report 📦

Path Size
lib/build/index.js 27.02 KB (+1.3% 🔺)
recipe/session/index.js 27.69 KB (+1.18% 🔺)
recipe/session/prebuiltui.js 32.58 KB (+1.07% 🔺)
recipe/thirdparty/index.js 34.78 KB (+0.99% 🔺)
recipe/emailpassword/index.js 14.17 KB (+2.33% 🔺)
recipe/emailverification/index.js 10.47 KB (+3.02% 🔺)
recipe/passwordless/index.js 18.04 KB (+1.76% 🔺)
recipe/emailverification/prebuiltui.js 37.36 KB (+1.09% 🔺)
recipe/thirdparty/prebuiltui.js 56.96 KB (+0.69% 🔺)
recipe/emailpassword/prebuiltui.js 43.9 KB (+0.89% 🔺)
recipe/passwordless/prebuiltui.js 131.75 KB (+0.3% 🔺)
recipe/multitenancy/index.js 9.32 KB (+3.75% 🔺)
recipe/multifactorauth/index.js 14.08 KB (+2.27% 🔺)
recipe/multifactorauth/prebuiltui.js 36.3 KB (+1.06% 🔺)
recipe/oauth2provider/index.js 10.09 KB (+3.47% 🔺)
recipe/oauth2provider/prebuiltui.js 34.71 KB (+1.1% 🔺)
recipe/webauthn/index.js 16.95 KB (+1.94% 🔺)
recipe/webauthn/prebuiltui.js 69.37 KB (+0.66% 🔺)

@bcbogdan bcbogdan force-pushed the feat/nextjs-ssr branch 2 times, most recently from b306f85 to ad89bbe Compare February 12, 2025 21:57
@bcbogdan bcbogdan changed the title Next.js SSR Improvements feat: Next.js SSR Improvements Feb 24, 2025
@bcbogdan bcbogdan force-pushed the feat/nextjs-ssr branch 2 times, most recently from 8231792 to 7c23d35 Compare February 24, 2025 14:26
@bcbogdan bcbogdan requested a review from porcellus February 24, 2025 14:42
@bcbogdan bcbogdan force-pushed the feat/nextjs-ssr branch 6 times, most recently from ebadbed to 3f9b519 Compare March 4, 2025 10:49
Update the function and add types

Add more info about the proposal

Account for pages directory in the function implementation

Update types and clean things up

Add comments

Add nextjs init function

Add the jose library

Fix refreshing and add example

Fix build and token config

Fix payload processing

Load config fron env variables

Add a redirect location during refresh

Refresh token from middleware

Move everything in the library

Rename files and update function singatures

Use the correct refresh path

Use normal responses instead of nextresponse

Use normal request instead of nextrequest

Cleanup implementation

Revoke session inside the middleware

Code review fixes

Add tests for getSSRSession

Add tests for middleware
@bcbogdan bcbogdan force-pushed the feat/nextjs-ssr branch from db16f4e to 3b1973c Compare May 5, 2025 07:52
@bcbogdan bcbogdan force-pushed the feat/nextjs-ssr branch from ff038f8 to 0c1ecca Compare May 7, 2025 07:58
@bcbogdan bcbogdan requested a review from porcellus May 7, 2025 08:01
@bcbogdan bcbogdan changed the base branch from master to 0.51 September 3, 2025 05:46
@bcbogdan
Copy link
Contributor Author

bcbogdan commented Sep 3, 2025

Nextjs is adding an unauthorized function that can be used inside server actions to return a 401 Response.

With that in mind I think we can drop the ensureSessionAndCall function and update getServerActionSession once the API becomes stable. The idea is to be able to do something like this: getServerActionSession(cookies, true) which will call unauthorized if the session needs to be refreshed.

@bcbogdan bcbogdan requested a review from porcellus September 3, 2025 13:19
@bcbogdan bcbogdan force-pushed the feat/nextjs-ssr branch 2 times, most recently from a380890 to 52ce968 Compare October 9, 2025 09:14
Comment on lines 206 to 211
export const getServerComponentSessionWithoutClaims =
SuperTokensNextjsSSRAPIWrapper.getServerComponentSessionWithoutClaims;
export const getServerActionSessionWithoutClaims = SuperTokensNextjsSSRAPIWrapper.getServerActionSessionWithoutClaims;
export const getServerSidePropsSessionWithoutClaims =
SuperTokensNextjsSSRAPIWrapper.getServerSidePropsSessionWithoutClaims;
export const ensureSessionAndCall = SuperTokensNextjsSSRAPIWrapper.ensureSessionAndCall;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export const getServerComponentSessionWithoutClaims =
SuperTokensNextjsSSRAPIWrapper.getServerComponentSessionWithoutClaims;
export const getServerActionSessionWithoutClaims = SuperTokensNextjsSSRAPIWrapper.getServerActionSessionWithoutClaims;
export const getServerSidePropsSessionWithoutClaims =
SuperTokensNextjsSSRAPIWrapper.getServerSidePropsSessionWithoutClaims;
export const ensureSessionAndCall = SuperTokensNextjsSSRAPIWrapper.ensureSessionAndCall;
export const getServerComponentSessionWithoutClaimValidation =
SuperTokensNextjsSSRAPIWrapper.getServerComponentSessionWithoutClaimValidation;
export const getServerActionSessionWithoutClaimValidation = SuperTokensNextjsSSRAPIWrapper.getServerActionSessionWithoutClaimValidation;
export const getServerSidePropsSessionWithoutClaimValidation =
SuperTokensNextjsSSRAPIWrapper.getServerSidePropsSessionWithoutClaimValidation;
export const ensureSessionAndCall = SuperTokensNextjsSSRAPIWrapper.ensureSessionAndCall;

cookies: CookiesStore
static async getServerActionSessionWithoutClaims(
cookies: CookiesStore,
requireAuth: boolean = false
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
requireAuth: boolean = false
requireAuth: boolean = true

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it should be on getServerComponentSessionWithoutClaims

Comment on lines 119 to 123
if (requireAuth) {
const redirectPath = cookies.get(CURRENT_PATH_COOKIE_NAME)?.value || "/";
const authPagePath = getAuthPagePath(redirectPath);
return redirect(authPagePath);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work here?

* @returns The session context value or directly redirects the user to either the login page or the refresh API
**/
static async getServerComponentSession(cookies: CookiesStore): Promise<LoadedSessionContext> {
static async getServerComponentSessionWithoutClaims(cookies: CookiesStore): Promise<SSRSessionContext> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be the one taking the requireAuth param

@porcellus porcellus merged commit 92e9aac into 0.51 Oct 22, 2025
31 of 32 checks passed
@porcellus porcellus deleted the feat/nextjs-ssr branch October 22, 2025 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants