5b. Session verification in getServerSideProps
note
This is applicable for when verifying a session in getServerSideProps
or getInitialProps
.
For this guide, we will assume that we want to pass the logged in user's ID as a prop to a protected route. An easier method to achieve this would be to directly get the user ID from the frontend, but for this example, we will pass it from the server side.
getSession
in getServerSideProps
#
1) We use important
If using getInitialProps
, the method described below applies as well. The only difference is the way the props are returned (see comments in the code).
An example of this can be found here.
import Session from 'supertokens-node/recipe/session'
import supertokensNode from 'supertokens-node'
import { backendConfig } from '../config/backendConfig'
export async function getServerSideProps(context: any) {
// this runs on the backend, so we must call init on supertokens-node SDK
supertokensNode.init(backendConfig())
// this will contain the session object post verification
let session
try {
// getSession will do session verification for us
session = await Session.getSession(context.req, context.res, {
overrideGlobalClaimValidators: () => {
// this makes it so that no custom session claims are checked
return []
}})
} catch (err: any) {
if (err.type === Session.Error.TRY_REFRESH_TOKEN) {
// in this case, the session is still valid, only the access token has expired.
// The refresh token is not sent to this route as it's tied to the /api/auth/session/refresh API paths.
// So we must send a "signal" to the frontend which will then call the
// refresh API and reload the page.
return { props: { fromSupertokens: 'needs-refresh' } }
// or return {fromSupertokens: 'needs-refresh'} in case of getInitialProps
} else if (err.type === Session.Error.UNAUTHORISED) {
// in this case, there is no session, or it has been revoked on the backend.
// either way, sending this response will make the frontend try and refresh
// which will fail and redirect the user to the login screen.
return { props: { fromSupertokens: 'needs-refresh' } }
}
throw err
}
// session verification is successful and we can pass
// the user's ID to the frontend.
return {
props: { userId: session!.getUserId() },
}
// or return {userId: session.getUserId()} in case of getInitialProps
}
caution
Do not use the verifySession
function here. The reason is that this will send a reply to the client in case of TRY_REFRESH_TOKEN
, and here, we want to catch that error and send a custom reply.
#
2) Doing manual refresh on the frontend- The following will refresh a session if needed, for all your website pages
- This goes in the
/pages/_app.tsx
file - An example of this can be found here.
import React, { useEffect } from "react";
import Session from 'supertokens-auth-react/recipe/session'
import { redirectToAuth } from 'supertokens-auth-react'
import { AppProps } from "next/app";
function MyApp({ Component, pageProps }: AppProps<{fromSupertokens: string}>) {
useEffect(() => {
async function doRefresh() {
// pageProps.fromSupertokens === 'needs-refresh' will be true
// when in getServerSideProps, getSession throws a TRY_REFRESH_TOKEN
// error.
if (pageProps.fromSupertokens === 'needs-refresh') {
if (await Session.attemptRefreshingSession()) {
// post session refreshing, we reload the page. This will
// send the new access token to the server, and then
// getServerSideProps will succeed
location.reload()
} else {
// the user's session has expired. So we redirect
// them to the login page
redirectToAuth()
}
}
}
doRefresh()
}, [pageProps.fromSupertokens])
if (pageProps.fromSupertokens === 'needs-refresh') {
// in case the frontend needs to refresh, we show nothing.
// Alternatively, you can show a spinner.
return null
}
// the below is already there by default
return <Component {...pageProps} />
}
export default MyApp
userId
returned by getServerSideProps in your component#
3) Consume the On success, getServerSideProps
returns
{
// Refer to Step 1)
props: { userId: session.getUserId() }
}
Therefore, the associated page can access the userId
like:
export default function Home(props: any) {
let userId = props.userId;
}