Session Verification using getSession
If you want to use a non-middleware form of verifySession
, you can use the getSession
function.
getSession
#
Using - NodeJS
- GoLang
- Python
- Express
- Hapi
- Fastify
- Koa
- Loopback
- AWS Lambda / Netlify
- Next.js
- NestJS
import express from "express";
import Session from "supertokens-node/recipe/session";
let app = express();
app.post("/like-comment", async (req, res, next) => {
try {
let session = await Session.getSession(req, res);
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
} catch (err) {
next(err);
}
});
import Hapi from "@hapi/hapi";
import Session from "supertokens-node/recipe/session";
let server = Hapi.server({ port: 8000 });
server.route({
path: "/like-comment",
method: "post",
handler: async (req, res) => {
let session = await Session.getSession(req, res);
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//...
}
})
import Fastify from "fastify";
import Session from "supertokens-node/recipe/session";
let fastify = Fastify();
fastify.post("/like-comment", async (req, res) => {
let session = await Session.getSession(req, res);
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
});
import Session from "supertokens-node/recipe/session";
import { middleware } from "supertokens-node/framework/awsLambda";
import { SessionEvent } from "supertokens-node/framework/awsLambda";
async function likeComment(awsEvent: SessionEvent) {
let session = await Session.getSession(awsEvent, awsEvent);
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
};
exports.handler = middleware(likeComment);
import KoaRouter from "koa-router";
import Session from "supertokens-node/recipe/session";
let router = new KoaRouter();
router.post("/like-comment", async (ctx, next) => {
let session = await Session.getSession(ctx, ctx);
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
});
import { inject } from "@loopback/core";
import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest";
import Session from "supertokens-node/recipe/session";
class LikeComment {
constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { }
@post("/like-comment")
@response(200)
async handler() {
let session = await Session.getSession(this.ctx, this.ctx);
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
}
}
import { superTokensNextWrapper } from 'supertokens-node/nextjs'
import Session from "supertokens-node/recipe/session";
import { SessionRequest } from "supertokens-node/framework/express";
export default async function likeComment(req: SessionRequest, res: any) {
let session = await superTokensNextWrapper(
async (next) => {
return await Session.getSession(req, res);
},
req,
res
)
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
}
import { Controller, Post, UseGuards, Req, Res } from "@nestjs/common";
import type { Request, Response } from "express";
import Session from "supertokens-node/recipe/session";
@Controller()
export class ExampleController {
@Post('example')
async postExample(@Req() req: Request, @Res({passthrough: true}) res: Response): Promise<boolean> {
// This should be done inside a parameter decorator, for more information please read our NestJS guide.
const session = await Session.getSession(req, res);
if (session === undefined) {
throw Error("Should never come here")
}
const userId = session.getUserId();
//....
return true;
}
}
import (
"fmt"
"net/http"
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/supertokens"
)
func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
sessionContainer, err := session.GetSession(r, w, nil)
if err != nil {
err = supertokens.ErrorHandler(err, r, w)
if err != nil {
// TODO: send 500 to client
}
return
}
userID := sessionContainer.GetUserID()
// TODO: API logic...
fmt.Println(userID)
}
- FastAPI
- Flask
- Django
from supertokens_python.recipe.session.asyncio import get_session
from fastapi.requests import Request
@app.post('/like-comment')
async def like_comment(request: Request):
session = await get_session(request)
if session is None:
raise Exception("Should never come here")
user_id = session.get_user_id()
print(user_id)
# TODO
from supertokens_python.recipe.session.syncio import get_session
from flask.wrappers import Request
@app.route('/like-comment', methods=['POST'])
def like_comment(request: Request):
session = get_session(request)
if session is None:
raise Exception("Should never come here")
user_id = session.get_user_id()
print(user_id)
# TODO
from supertokens_python.recipe.session.asyncio import get_session
from django.http import HttpRequest
async def like_comment(request: HttpRequest):
session = await get_session(request)
if session is None:
raise Exception("Should never come here")
user_id = session.get_user_id()
print(user_id) # TODO
session
object#
The This object exposes the following functions:
getHandle
: Returns thesessionHandle
for this session. This is a constant, unique string per session that never changes for its session.getUserId
: Returns the userId of logged in usergetSessionData
: Returns the session data (stored in the database) that is associated with the session.updateSessionData
: Set a new JSON object to the session data (stored in the database)getAccessTokenPayload
: Returns the access token's payload for this session.mergeIntoAccessTokenPayload
: Adds key / values into a JSON object in the access token. Set a key tonull
to remove it from the payload.revokeSession
: Destroys this session in the db and on the frontendgetTimeCreated
: Returns the time in milliseconds of when this session was createdgetExpiry
: Returns the time in milliseconds of when this session will expire if not refreshed.getAccessToken
: Returns the rawstring
access token
getSessionData
vs getAccessTokenPayload
#
getSessionData
queries the SuperTokens Core to get the information, mapped to that session's handle, from the database. WhereasgetAccessTokenPayload
reads directly from the access token used in the request.getSessionData
is much slower since it requires a network call.- The information stored using
updateSessionData
(changes the result ofgetSessionData
function call), is not exposed to the frontend in any way. So if you want to store something sensitive against the session handle, use this method. - If you want access to some information in most / all API, like the user's role, then use
getAccessTokenPayload
andmergeIntoAccessTokenPayload
since fetching this information from the session will be very fast (no network call required).
#
Optional session verificationSometimes, you want an API to be accessible even if there is no session. In that case, you can use the sessionRequired
flag:
- NodeJS
- GoLang
- Python
- Express
- Hapi
- Fastify
- Koa
- Loopback
- AWS Lambda / Netlify
- Next.js
- NestJS
import express from "express";
import Session from "supertokens-node/recipe/session";
let app = express();
app.post("/like-comment", async (req, res, next) => {
try {
let session = await Session.getSession(req, res, { sessionRequired: false })
if (session !== undefined) {
let userId = session.getUserId();
} else {
// user is not logged in...
}
//....
} catch (err) {
next(err);
}
});
import Hapi from "@hapi/hapi";
import Session from "supertokens-node/recipe/session";
let server = Hapi.server({ port: 8000 });
server.route({
path: "/like-comment",
method: "post",
handler: async (req, res) => {
let session = await Session.getSession(req, res, { sessionRequired: false })
if (session !== undefined) {
let userId = session.getUserId();
} else {
// user is not logged in...
}
//...
}
})
import Fastify from "fastify";
import Session from "supertokens-node/recipe/session";
let fastify = Fastify();
fastify.post("/like-comment", async (req, res) => {
let session = await Session.getSession(req, res, { sessionRequired: false })
if (session !== undefined) {
let userId = session.getUserId();
} else {
// user is not logged in...
}
//....
});
import Session from "supertokens-node/recipe/session";
import { middleware } from "supertokens-node/framework/awsLambda";
import { SessionEvent } from "supertokens-node/framework/awsLambda";
async function likeComment(awsEvent: SessionEvent) {
let session = await Session.getSession(awsEvent, awsEvent, { sessionRequired: false })
if (session !== undefined) {
let userId = session.getUserId();
} else {
// user is not logged in...
}
//....
};
exports.handler = middleware(likeComment);
import KoaRouter from "koa-router";
import Session from "supertokens-node/recipe/session";
let router = new KoaRouter();
router.post("/like-comment", async (ctx, next) => {
let session = await Session.getSession(ctx, ctx, { sessionRequired: false })
if (session !== undefined) {
let userId = session.getUserId();
} else {
// user is not logged in...
}
//....
});
import { inject } from "@loopback/core";
import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest";
import Session from "supertokens-node/recipe/session";
class LikeComment {
constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { }
@post("/like-comment")
@response(200)
async handler() {
let session = await Session.getSession(this.ctx, this.ctx, { sessionRequired: false })
if (session !== undefined) {
let userId = session.getUserId();
} else {
// user is not logged in...
}
//....
}
}
import { superTokensNextWrapper } from 'supertokens-node/nextjs'
import Session from "supertokens-node/recipe/session";
import { SessionRequest } from "supertokens-node/framework/express";
export default async function likeComment(req: SessionRequest, res: any) {
let session = await superTokensNextWrapper(
async (next) => {
return await Session.getSession(req, res, { sessionRequired: false });
},
req,
res
)
if (session !== undefined) {
let userId = session.getUserId();
} else {
// user is not logged in...
}
//....
}
import { Controller, Post, UseGuards, Req, Res } from "@nestjs/common";
import type { Request, Response } from "express";
import Session from "supertokens-node/recipe/session";
@Controller()
export class ExampleController {
@Post('example')
async postExample(@Req() req: Request, @Res({ passthrough: true }) res: Response): Promise<boolean> {
// This should be done inside a parameter decorator, for more information please read our NestJS guide.
const session = await Session.getSession(req, res, { sessionRequired: false })
if (session !== undefined) {
const userId = session.getUserId();
} else {
// user is not logged in...
}
//....
return true;
}
}
import (
"fmt"
"net/http"
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
"github.com/supertokens/supertokens-golang/supertokens"
)
func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
sessionRequired := false
sessionContainer, err := session.GetSession(r, w, &sessmodels.VerifySessionOptions{
SessionRequired: &sessionRequired,
})
if err != nil {
err = supertokens.ErrorHandler(err, r, w)
if err != nil {
// TODO: send 500 to client
}
return
}
if sessionContainer != nil {
// session exists
userID := sessionContainer.GetUserID()
fmt.Println(userID)
} else {
// user is not logged in
}
}
- FastAPI
- Flask
- Django
from supertokens_python.recipe.session.asyncio import get_session
from fastapi import Request
@app.post('/like-comment')
async def like_comment(request: Request):
session = await get_session(request, session_required=False)
if session is not None:
user_id = session.get_user_id()
print(user_id) # TODO:
else:
pass # user is not logged in
from supertokens_python.recipe.session.syncio import get_session
from flask.wrappers import Request
@app.route('/like-comment', methods=['POST'])
def like_comment(request: Request):
session = get_session(request, session_required=False)
if session is not None:
user_id = session.get_user_id()
print(user_id) # TODO..
else:
pass # user is not logged in
from django.http import HttpRequest
from supertokens_python.recipe.session.asyncio import get_session
async def like_comment(request: HttpRequest):
session = await get_session(request, session_required=False)
if session is not None:
user_id = session.get_user_id()
print(user_id) # TODO..
else:
pass # user is not logged in
#
Verifying the claims of a sessionSometimes, you may also want to check if there are certain claims in the session as part of the verification process. For example, you may want to check that the session has the admin
role claim for certain APIs, or that the user has completed 2FA.
This can be done using our session claims validator feature. Let's take an example of using the user roles claim to check if the session has the admin claim:
- NodeJS
- GoLang
- Python
- Express
- Hapi
- Fastify
- Koa
- Loopback
- AWS Lambda / Netlify
- Next.js
- NestJS
import express from "express";
import Session from "supertokens-node/recipe/session";
import UserRoles from "supertokens-node/recipe/userroles";
let app = express();
app.post("/like-comment", async (req, res, next) => {
try {
let session = await Session.getSession(req, res, {
overrideGlobalClaimValidators: async (globalValidators) => [
...globalValidators,
UserRoles.UserRoleClaim.validators.includes("admin"),
// UserRoles.PermissionClaim.validators.includes("edit")
]
});
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
} catch (err) {
next(err)
}
});
import Hapi from "@hapi/hapi";
import Session from "supertokens-node/recipe/session";
import UserRoles from "supertokens-node/recipe/userroles";
let server = Hapi.server({ port: 8000 });
server.route({
path: "/like-comment",
method: "post",
handler: async (req, res) => {
let session = await Session.getSession(req, res, {
overrideGlobalClaimValidators: async (globalValidators) => [
...globalValidators,
UserRoles.UserRoleClaim.validators.includes("admin"),
// UserRoles.PermissionClaim.validators.includes("edit")
]
});
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//...
}
})
import Fastify from "fastify";
import Session from "supertokens-node/recipe/session";
import UserRoles from "supertokens-node/recipe/userroles";
let fastify = Fastify();
fastify.post("/like-comment", async (req, res) => {
let session = await Session.getSession(req, res, {
overrideGlobalClaimValidators: async (globalValidators) => [
...globalValidators,
UserRoles.UserRoleClaim.validators.includes("admin"),
// UserRoles.PermissionClaim.validators.includes("edit")
]
});
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
});
import Session from "supertokens-node/recipe/session";
import { middleware } from "supertokens-node/framework/awsLambda";
import { SessionEvent } from "supertokens-node/framework/awsLambda";
import UserRoles from "supertokens-node/recipe/userroles";
async function likeComment(awsEvent: SessionEvent) {
let session = await Session.getSession(awsEvent, awsEvent, {
overrideGlobalClaimValidators: async (globalValidators) => [
...globalValidators,
UserRoles.UserRoleClaim.validators.includes("admin"),
// UserRoles.PermissionClaim.validators.includes("edit")
]
});
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
};
exports.handler = middleware(likeComment);
import KoaRouter from "koa-router";
import Session from "supertokens-node/recipe/session";
import UserRoles from "supertokens-node/recipe/userroles";
let router = new KoaRouter();
router.post("/like-comment", async (ctx, next) => {
let session = await Session.getSession(ctx, ctx, {
overrideGlobalClaimValidators: async (globalValidators) => [
...globalValidators,
UserRoles.UserRoleClaim.validators.includes("admin"),
// UserRoles.PermissionClaim.validators.includes("edit")
]
});
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
});
import { inject } from "@loopback/core";
import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest";
import Session from "supertokens-node/recipe/session";
import UserRoles from "supertokens-node/recipe/userroles";
class LikeComment {
constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { }
@post("/like-comment")
@response(200)
async handler() {
let session = await Session.getSession(this.ctx, this.ctx, {
overrideGlobalClaimValidators: async (globalValidators) => [
...globalValidators,
UserRoles.UserRoleClaim.validators.includes("admin"),
// UserRoles.PermissionClaim.validators.includes("edit")
]
});
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
}
}
import { superTokensNextWrapper } from 'supertokens-node/nextjs'
import Session from "supertokens-node/recipe/session";
import { SessionRequest } from "supertokens-node/framework/express";
import UserRoles from "supertokens-node/recipe/userroles";
export default async function likeComment(req: SessionRequest, res: any) {
let session = await superTokensNextWrapper(
async (next) => {
return await Session.getSession(req, res, {
overrideGlobalClaimValidators: async (globalValidators) => [
...globalValidators,
UserRoles.UserRoleClaim.validators.includes("admin"),
// UserRoles.PermissionClaim.validators.includes("edit")
]
});
},
req,
res
)
if (session === undefined) {
throw Error("Should never come here")
}
let userId = session.getUserId();
//....
}
import { Controller, Post, UseGuards, Req, Res } from "@nestjs/common";
import type { Request, Response } from "express";
import Session from "supertokens-node/recipe/session";
import UserRoles from "supertokens-node/recipe/userroles";
@Controller()
export class ExampleController {
@Post('example')
async postExample(@Req() req: Request, @Res({passthrough: true}) res: Response): Promise<boolean> {
// This should be done inside a parameter decorator, for more information please read our NestJS guide.
const session = await Session.getSession(req, res, {
overrideGlobalClaimValidators: async (globalValidators) => [
...globalValidators,
UserRoles.UserRoleClaim.validators.includes("admin"),
// UserRoles.PermissionClaim.validators.includes("edit")
]
});
if (session === undefined) {
throw Error("Should never come here")
}
const userId = session.getUserId();
//....
return true;
}
}
import (
"fmt"
"net/http"
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/session/claims"
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
"github.com/supertokens/supertokens-golang/recipe/userroles/userrolesclaims"
"github.com/supertokens/supertokens-golang/supertokens"
)
func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
sessionContainer, err := session.GetSession(r, w, &sessmodels.VerifySessionOptions{
OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) {
globalClaimValidators = append(globalClaimValidators, userrolesclaims.UserRoleClaimValidators.Includes("admin", nil, nil))
return globalClaimValidators, nil
},
})
if err != nil {
err = supertokens.ErrorHandler(err, r, w)
if err != nil {
// TODO: send 500 to client
}
return
}
userID := sessionContainer.GetUserID()
// TODO: API logic...
fmt.Println(userID)
}
- FastAPI
- Flask
- Django
from supertokens_python.recipe.session.asyncio import get_session
from fastapi.requests import Request
from supertokens_python.recipe.userroles import UserRoleClaim
@app.post('/like-comment')
async def like_comment(request: Request):
session = await get_session(request,
override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \
[UserRoleClaim.validators.includes("admin")])
if session is None:
raise Exception("Should never come here")
user_id = session.get_user_id()
print(user_id)
# TODO
from supertokens_python.recipe.session.syncio import get_session
from flask.wrappers import Request
from supertokens_python.recipe.userroles import UserRoleClaim
@app.route('/like-comment', methods=['POST'])
def like_comment(request: Request):
session = get_session(request,
override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \
[UserRoleClaim.validators.includes("admin")])
if session is None:
raise Exception("Should never come here")
user_id = session.get_user_id()
print(user_id)
# TODO
from supertokens_python.recipe.session.asyncio import get_session
from django.http import HttpRequest
from supertokens_python.recipe.userroles import UserRoleClaim
async def like_comment(request: HttpRequest):
session = await get_session(request,
override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \
[UserRoleClaim.validators.includes("admin")])
if session is None:
raise Exception("Should never come here")
user_id = session.get_user_id()
print(user_id) # TODO
- We add the
UserRoleClaim
validator to theverifySession
function which makes sure that the user has anadmin
role. - The
globalValidators
represents other validators that apply to all API routes by default. This may include a validator that enforces that the user's email is verified (if enabled by you). - We can also add a
PermissionClaim
validator to enforce a permission.
feature
You can also build your own custom claim validators based on your app's requirements.
getSession
vs verifySession
#
Both these functions do session verification. However, verifySession
is a middleware that returns a reply directly to the frontend if the input access token is invalid or expired. On the other hand, getSession
is a function which returns a session object on successful verification, and throws an exception which can be handled by you in case the access token is expired or is invalid.
Internally, verifySession
uses getSession
in the following way:
- NodeJS
- GoLang
- Python
import { VerifySessionOptions } from "supertokens-node/recipe/session/types";
import { errorHandler } from "supertokens-node/framework/express";
import { NextFunction, Request, Response } from "express";
import Session from "supertokens-node/recipe/session";
import { Error as SuperTokensError } from "supertokens-node";
function verifySession(options?: VerifySessionOptions) {
return async (req: Request, res: Response, next: NextFunction) => {
try {
if (options?.sessionRequired === false) {
(req as any).session = await Session.getSession(req, res, {
antiCsrfCheck: options?.antiCsrfCheck,
overrideGlobalClaimValidators: options?.overrideGlobalClaimValidators,
sessionRequired: false
});
} else {
(req as any).session = await Session.getSession(req, res, {
antiCsrfCheck: options?.antiCsrfCheck,
overrideGlobalClaimValidators: options?.overrideGlobalClaimValidators,
sessionRequired: true
});
}
next();
} catch (err) {
if (SuperTokensError.isErrorFromSuperTokens(err)) {
if (err.type === Session.Error.TRY_REFRESH_TOKEN) {
// This means that the session exists, but the access token
// has expired.
// You can handle this in a custom way by sending a 401.
// Or you can call the errorHandler middleware as shown below
} else if (err.type === Session.Error.UNAUTHORISED) {
// This means that the session does not exist anymore.
// You can handle this in a custom way by sending a 401.
// Or you can call the errorHandler middleware as shown below
} else if (err.type === Session.Error.TOKEN_THEFT_DETECTED) {
// Session hijacking attempted. You should revoke the session
// using Session.revokeSession fucntion and send a 401
} else if (err.type === Session.Error.INVALID_CLAIMS) {
// The user is missing some required claim.
// You can pass the missing claims to the frontend and handle it there
}
// OR you can use this errorHandler which will
// handle all of the above errors in the default way
errorHandler()(err, req, res, (err) => {
next(err)
})
} else {
next(err)
}
}
};
}
The errorHandler
will send a 401
reply to the frontend if the getSession
function throws an exception indicating that the session does not exist or if the access token has expired.
import (
"context"
"net/http"
defaultErrors "errors"
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/session/errors"
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
"github.com/supertokens/supertokens-golang/supertokens"
)
func VerifySession(options *sessmodels.VerifySessionOptions, otherHandler http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
session.GetSession(r, w, options)
session, err := session.GetSession(r, w, options)
if err != nil {
if defaultErrors.As(err, &errors.TryRefreshTokenError{}) {
// This means that the session exists, but the access token
// has expired.
// You can handle this in a custom way by sending a 401.
// Or you can call the errorHandler middleware as shown below
} else if defaultErrors.As(err, &errors.UnauthorizedError{}) {
// This means that the session does not exist anymore.
// You can handle this in a custom way by sending a 401.
// Or you can call the errorHandler middleware as shown below
} else if defaultErrors.As(err, &errors.TokenTheftDetectedError{}) {
// Session hijacking attempted. You should revoke the session
// using Session.revokeSession fucntion and send a 401
} else if defaultErrors.As(err, &errors.InvalidClaimError{}) {
// The user is missing some required claim.
// You can pass the missing claims to the frontend and handle it there
}
// OR you can use this errorHandler which will
// handle all of the above errors in the default way
err = supertokens.ErrorHandler(err, r, w)
if err != nil {
// TODO: send a 500 error to the frontend
}
return
}
if session != nil {
ctx := context.WithValue(r.Context(), sessmodels.SessionContext, session)
otherHandler(w, r.WithContext(ctx))
} else {
otherHandler(w, r)
}
})
}
The supertokens.ErrorHandler
will send a 401
reply to the frontend if the getSession
function throws an exception indicating that the session does not exist or if the access token has expired.
from functools import wraps
from typing import Any, Callable, Dict, TypeVar, Union, cast, List, Optional
from supertokens_python.framework.flask.flask_request import FlaskRequest
from supertokens_python.recipe.session.syncio import get_session
from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.interfaces import SessionClaimValidator
from supertokens_python.types import MaybeAwaitable
from supertokens_python.recipe.session.exceptions import (
TokenTheftError,
UnauthorisedError,
InvalidClaimsError,
TryRefreshTokenError
)
_T = TypeVar("_T", bound=Callable[..., Any])
def verify_session(
anti_csrf_check: Union[bool, None] = None,
session_required: bool = True,
override_global_claim_validators: Optional[
Callable[
[List[SessionClaimValidator], SessionContainer, Dict[str, Any]],
MaybeAwaitable[List[SessionClaimValidator]],
]
] = None,
) -> Callable[[_T], _T]:
def session_verify(f: _T) -> _T:
@wraps(f)
def wrapped_function(*args: Any, **kwargs: Any):
from flask import make_response, request
baseRequest = FlaskRequest(request)
try:
session = get_session(baseRequest,
anti_csrf_check,
session_required,
override_global_claim_validators)
except Exception as e:
if isinstance(e, TryRefreshTokenError):
# This means that the session exists, but the access token
# has expired.
# You can handle this in a custom way by sending a 401.
# Or you can call the errorHandler middleware as shown below
pass
if isinstance(e, UnauthorisedError):
# This means that the session does not exist anymore.
# You can handle this in a custom way by sending a 401.
# Or you can call the errorHandler middleware as shown below
pass
if isinstance(e, TokenTheftError):
# Session hijacking attempted. You should revoke the session
# using Session.revokeSession fucntion and send a 401
pass
if isinstance(e, InvalidClaimsError):
# The user is missing some required claim.
# You can pass the missing claims to the frontend and handle it there
pass
# OR you can raise this error which will
# handle all of the above errors in the default way
raise e
if session is None:
if session_required:
raise Exception("Should never come here")
baseRequest.set_session_as_none()
else:
baseRequest.set_session(session)
response = make_response(f(*args, **kwargs))
return response
return cast(_T, wrapped_function)
return session_verify
If get_session
throws an error (in case the input access token is invalid or has expired), then the SuperTokens middleware added to your app will handle that exception and send a 401
to the frontend.
important
You should use getSession
only if you want to handle exception cases on your own, or if you want to build your own session verification middleware instead of using verifySession
that's provided by us.