Skip to main content
Which UI do you use?
Custom UI
Pre built UI

Session verification during server side rendering


Getting access to the session during server side rendering is only possible using cookie-based sessions. This is the default setting, but you have to keep this in mind if you want to switch to header-based sessions.

1) Enable sharing of cookies across sub domains#

If your API layer and website are on different sub domains (like and, then by default, the session tokens are attached only to You want to change this so that the session tokens are attached to so that the access token cookie is sent to your webserver on as well. This can be enabled by setting the cookieDomain config on the backend.

2) Do JWT verification#

Follow the JWT verification guide to verify the JWT on the server side. You can read the JWT from the sAccessToken cookie in the request object. If the JWT is missing, or is invalid, or has expired, you should redirect the user to a /refresh-session?redirectBack=<current route> page (you can have any path for this since it's your website).

On the /refresh-session page, you want to call the attemptRefreshingSession function (from the client side). This function will attempt to refresh the session. If it succeeds, it will return true. If it fails, it will return false. If it returns true, you want to redirect the user back to the page they were on. If it returns false, you want to redirect the user to the login page.

3) Implementing the refresh session flow (/refresh-session page)#

On this path, we want to attempt refreshing the session which can yield:

  • Success: The frontend will get new access and refresh tokens. Post this, we want to redirect the user to the path mentioned on the redirectBack query param.
  • Failure: This would happen if the session has expired or has been revoked from the backend. Either way, you want to redirect the user to the login page.

Below is the code snippet that you can use on the /refresh-session path on the frontend

import React from "react";
import Session from "supertokens-auth-react/recipe/session"
import SuperTokens from "supertokens-auth-react";

export function AttemptRefresh(props: any) {
React.useEffect(() => {
let cancel = false;
Session.attemptRefreshingSession().then(success => {
if (cancel) {
// component has unmounted somehow..
if (success) {
// we have new session tokens, so we redirect the user back
// to where they were.
const urlParams = new URLSearchParams(;
window.location.href = urlParams.get('redirectBack')!;
} else {
// we redirect to the login page since the user
// is now logged out
return () => {
cancel = true;
}, []);
return null;

Why do we trigger the refresh session flow instead of redirecting the user to the login page directly?#

There are two reasons why JWT verification can fail:

  • The session tokens were not passed from the frontend: This can happen if the route is called when the user has logged out.
  • The session tokens are passed from the frontend, but the JWT has expired.

If we redirect the user to the login page directly, then in the second case, the frontend will redirect the user back to the current route (since the refresh token is still valid) causing an infinite loop. To counteract this issue, we redirect the user to refresh page which will cause a new access token to be minted. In the first case, when the user is actually logged out, the refreshing will fail, and they will be redirected to the login page anyway.

Can I use verifySession or getSession instead of manual JWT verification?#

Yes you can, but we do not recommend it because:

  • Often the webserver is on a different process than the API server. Using our backend SDK requires you to give it the credentials to the SuperTokens core, which you might not want to provide to the webserver.
  • The session object resulting from verifySession and getSession makes it very easy to mutate the access token payload. These mutations are reflected on the frontend via network interceptors from our frontend SDK. But in SSR, the browser makes the call to your webserver direclty, so our frontend SDK interceptors don't run. This can cause inconsistency between the access token payload as seen on the frontend vs the backend.