Access Token Blacklisting
By default, session verification is stateless. This means that SuperTokens does not check that the session actually exists in the database, and only verifies the session by checking it's signature. Whilst this makes session verifications fast, it also means that if a session is revoked, the user will still be able to use it until the access token expires.
If you want session verifications to fail immediately after the session has revoked, you should use this feature. Since you can use this feature on a per API basis, we recommend that you only use it for non GET APIs since only those are state changing.
This feature works by passing the checkDatabase
option when verifying the session as shown below.
verifySession
middleware#
Using the - NodeJS
- GoLang
- Python
- Other Frameworks
Important
For other backend frameworks, you can follow our guide on how to spin up a separate server configured with the SuperTokens backend SDK to authenticate requests and issue session tokens.
- Express
- Hapi
- Fastify
- Koa
- Loopback
- AWS Lambda / Netlify
- Next.js
- NestJS
import express from "express";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import { SessionRequest } from "supertokens-node/framework/express";
let app = express();
app.post("/like-comment", verifySession({ checkDatabase: true }), (req: SessionRequest, res) => {
let userId = req.session!.getUserId();
//....
});
import Hapi from "@hapi/hapi";
import { verifySession } from "supertokens-node/recipe/session/framework/hapi";
import { SessionRequest } from "supertokens-node/framework/hapi";
let server = Hapi.server({ port: 8000 });
server.route({
path: "/like-comment",
method: "post",
options: {
pre: [
{
method: verifySession({ checkDatabase: true })
},
],
},
handler: async (req: SessionRequest, res) => {
let userId = req.session!.getUserId();
//...
}
})
import Fastify from "fastify";
import { verifySession } from "supertokens-node/recipe/session/framework/fastify";
import { SessionRequest } from "supertokens-node/framework/fastify";
let fastify = Fastify();
fastify.post("/like-comment", {
preHandler: verifySession({ checkDatabase: true }),
}, (req: SessionRequest, res) => {
let userId = req.session!.getUserId();
//....
});
import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda";
import { SessionEventV2 } from "supertokens-node/framework/awsLambda";
async function likeComment(awsEvent: SessionEventV2) {
let userId = awsEvent.session!.getUserId();
//....
};
exports.handler = verifySession(likeComment, { checkDatabase: true });
import KoaRouter from "koa-router";
import { verifySession } from "supertokens-node/recipe/session/framework/koa";
import { SessionContext } from "supertokens-node/framework/koa";
let router = new KoaRouter();
router.post("/like-comment", verifySession({ checkDatabase: true }), (ctx: SessionContext, next) => {
let userId = ctx.session!.getUserId();
//....
});
import { inject, intercept } from "@loopback/core";
import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest";
import { verifySession } from "supertokens-node/recipe/session/framework/loopback";
import { SessionContext } from "supertokens-node/framework/loopback";
class LikeComment {
constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { }
@post("/like-comment")
@intercept(verifySession({ checkDatabase: true }))
@response(200)
handler() {
let userId = (this.ctx as SessionContext).session!.getUserId();
//....
}
}
import { superTokensNextWrapper } from 'supertokens-node/nextjs'
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import { SessionRequest } from "supertokens-node/framework/express";
export default async function likeComment(req: SessionRequest, res: any) {
await superTokensNextWrapper(
async (next) => {
await verifySession({ checkDatabase: true })(req, res, next);
},
req,
res
)
let userId = req.session!.getUserId();
//....
}
import { Controller, Post, UseGuards, Session } from "@nestjs/common";
import { SessionContainer } from "supertokens-node/recipe/session";
import { AuthGuard } from './auth/auth.guard';
@Controller()
export class ExampleController {
@Post('example')
@UseGuards(new AuthGuard({ checkDatabase: true })) // For more information about this guard please read our NestJS guide.
async postExample(@Session() session: SessionContainer): Promise<boolean> {
let userId = session.getUserId();
//....
return true;
}
}
- Chi
- net/http
- Gin
- Mux
import (
"fmt"
"net/http"
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
)
func main() {
_ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
// Wrap the API handler in session.VerifySession
checkDb := true
session.VerifySession(&sessmodels.VerifySessionOptions{
CheckDatabase: &checkDb,
}, likeCommentAPI).ServeHTTP(rw, r)
})
}
func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
// retrieve the session object as shown below
sessionContainer := session.GetSessionFromRequestContext(r.Context())
userID := sessionContainer.GetUserID()
fmt.Println(userID)
}
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
)
func main() {
router := gin.New()
// Wrap the API handler in session.VerifySession
checkDb := true
router.POST("/likecomment", verifySession(&sessmodels.VerifySessionOptions{
CheckDatabase: &checkDb,
}), likeCommentAPI)
}
// This is a function that wraps the supertokens verification function
// to work the gin
func verifySession(options *sessmodels.VerifySessionOptions) gin.HandlerFunc {
return func(c *gin.Context) {
session.VerifySession(options, func(rw http.ResponseWriter, r *http.Request) {
c.Request = c.Request.WithContext(r.Context())
c.Next()
})(c.Writer, c.Request)
// we call Abort so that the next handler in the chain is not called, unless we call Next explicitly
c.Abort()
}
}
func likeCommentAPI(c *gin.Context) {
// retrieve the session object as shown below
sessionContainer := session.GetSessionFromRequestContext(c.Request.Context())
userID := sessionContainer.GetUserID()
fmt.Println(userID)
}
import (
"fmt"
"net/http"
"github.com/go-chi/chi"
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
)
func main() {
r := chi.NewRouter()
// Wrap the API handler in session.VerifySession
checkDb := true
r.Post("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{
CheckDatabase: &checkDb,
}, likeCommentAPI))
}
func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
// retrieve the session object as shown below
sessionContainer := session.GetSessionFromRequestContext(r.Context())
userID := sessionContainer.GetUserID()
fmt.Println(userID)
}
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
)
func main() {
router := mux.NewRouter()
// Wrap the API handler in session.VerifySession
checkDb := true
router.HandleFunc("/likecomment", session.VerifySession(&sessmodels.VerifySessionOptions{
CheckDatabase: &checkDb,
}, likeCommentAPI)).Methods(http.MethodPost)
}
func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
// retrieve the session object as shown below
sessionContainer := session.GetSessionFromRequestContext(r.Context())
userID := sessionContainer.GetUserID()
fmt.Println(userID)
}
- FastAPI
- Flask
- Django
from supertokens_python.recipe.session.framework.fastapi import verify_session
from supertokens_python.recipe.session import SessionContainer
from fastapi import Depends
@app.post('/like_comment')
async def like_comment(session: SessionContainer = Depends(verify_session(check_database=True))):
user_id = session.get_user_id()
print(user_id)
from supertokens_python.recipe.session.framework.flask import verify_session
from supertokens_python.recipe.session import SessionContainer
from flask import g
@app.route('/update-jwt', methods=['POST'])
@verify_session(check_database=True)
def like_comment():
session: SessionContainer = g.supertokens
user_id = session.get_user_id()
print(user_id)
from supertokens_python.recipe.session.framework.django.asyncio import verify_session
from django.http import HttpRequest
from supertokens_python.recipe.session import SessionContainer
@verify_session(check_database=True)
async def like_comment(request: HttpRequest):
session: SessionContainer = request.supertokens
user_id = session.get_user_id()
print(user_id)
getSession
#
Using - NodeJS
- GoLang
- Python
- Other Frameworks
Important
For other backend frameworks, you can follow our guide on how to spin up a separate server configured with the SuperTokens backend SDK to authenticate requests and issue session tokens.
- 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, { checkDatabase: true })
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, { checkDatabase: true })
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, { checkDatabase: true })
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, { checkDatabase: true })
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, { checkDatabase: true })
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, { checkDatabase: true })
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, { checkDatabase: true });
},
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, { checkDatabase: true })
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) {
checkDb := true
sessionContainer, err := session.GetSession(r, w, &sessmodels.VerifySessionOptions{
CheckDatabase: &checkDb,
})
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, check_database=True)
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, check_database=True)
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, check_database=True)
if session is not None:
user_id = session.get_user_id()
print(user_id) # TODO..
else:
pass # user is not logged in