Skip to content
Esc
navigateopen⌘Jpreview
Dashboard
On this page

Session Invalidation

Learn how to handle session expiry, implement sign out, and revoke sessions across different programming languages and frameworks.

Overview

You can invalidate a session in SuperTokens in different ways. The main recommendation is to use the signOut function from the frontend SDK. Besides that you can also revoke sessions manually, through the backend SDKs. This guide shows you how to implement each of these.

Before you start


User sign out

The frontend SDK exposes a signOut function that revokes the session for the user. You need to add your own UI element for this since the library does not expose any components. The signOut function calls the sign out API exposed by the session recipe on the backend and revokes the current session. It does not revoke the user’s other sessions. Use the explicit all-session API shown below when that is the intended behavior. If you call the signOut function whilst the access token has expired, but the refresh token still exists, the SDKs automatically perform a session refresh before revoking the session.

UI type
import React from "react";
import { signOut } from "supertokens-auth-react/recipe/session";

function NavBar() {
  async function onLogout() {
    await signOut();
    window.location.href = "/auth"; // or redirect to wherever the login page is
  }
  return (
    <ul>
      <li>Home</li>
      <li onClick={onLogout}>Logout</li>
    </ul>
  );
}
import Session from "supertokens-web-js/recipe/session";

async function logout() {
  await Session.signOut();
  window.location.href = "/auth"; // or redirect to wherever the login page is
}

Expose a backend sign out method

If you do not want to use the frontend function you can expose a backend sign out method.

Next.js router
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("/someapi", verifySession(), async (req: SessionRequest, res) => {
  // This will delete the session from the db and from the frontend (cookies)
  await req.session!.revokeSession();

  res.send("Success! User session revoked");
});
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: "/someapi",
  method: "post",
  options: {
    pre: [
      {
        method: verifySession(),
      },
    ],
  },
  handler: async (req: SessionRequest, res) => {
    // This will delete the session from the db and from the frontend (cookies)
    await req.session!.revokeSession();
    return res.response("Success! User session revoked").code(200);
  },
});
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(
  "/someapi",
  {
    preHandler: verifySession(),
  },
  async (req: SessionRequest, res) => {
    // This will delete the session from the db and from the frontend (cookies)
    await req.session!.revokeSession();

    res.send("Success! User session revoked");
  },
);
import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda";
import { SessionEvent } from "supertokens-node/framework/awsLambda";

async function someapi(awsEvent: SessionEvent) {
  // This will delete the session from the db and from the frontend (cookies)
  await awsEvent.session!.revokeSession();

  return {
    body: JSON.stringify({ message: "Success! User session revoked" }),
    statusCode: 200,
  };
}

exports.handler = verifySession(someapi);
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("/someapi", verifySession(), async (ctx: SessionContext, next) => {
  // This will delete the session from the db and from the frontend (cookies)
  await ctx.session!.revokeSession();

  ctx.body = "Success! User session revoked";
});
import { inject, intercept } from "@loopback/core";
import { RestBindings, post, response } from "@loopback/rest";
import { verifySession } from "supertokens-node/recipe/session/framework/loopback";
import { SessionContext } from "supertokens-node/framework/loopback";

class Logout {
  constructor(@inject(RestBindings.Http.CONTEXT) private ctx: SessionContext) {}
  @post("/someapi")
  @intercept(verifySession())
  @response(200)
  async handler() {
    // This will delete the session from the db and from the frontend (cookies)
    await this.ctx.session!.revokeSession();

    return "Success! User session revoked";
  }
}
import { Controller, Post, UseGuards, Request, Response, Session } from "@nestjs/common";
import { SessionContainer } from "supertokens-node/recipe/session";
import { AuthGuard } from "./auth/auth.guard";

@Controller()
export class ExampleController {
  // For more information about "AuthGuard" and the "Session" decorator please read our NestJS guide.
  @Post("someapi")
  @UseGuards(new AuthGuard())
  async postSomeAPI(@Session() session: SessionContainer): Promise<string> {
    await session.revokeSession();

    return "Success! User session revoked";
  }
}
import (
	"net/http"

	"github.com/supertokens/supertokens-golang/recipe/session"
	"github.com/supertokens/supertokens-golang/supertokens"
)

func someAPI(w http.ResponseWriter, r *http.Request) {
	// retrieve the session object as shown below
	sessionContainer := session.GetSessionFromRequestContext(r.Context())

	// This will delete the session from the db and from the frontend (cookies)
	err := sessionContainer.RevokeSession()
	if err != nil {
		err = supertokens.ErrorHandler(err, r, w)
		if err != nil {
			// TODO: Send 500 status code to client
		}
		return
	}

	// TODO: Send 200 response to client
}
from supertokens_python.recipe.session.framework.fastapi import verify_session
from supertokens_python.recipe.session import SessionContainer
from fastapi import Depends
from fastapi.responses import PlainTextResponse

async def some_api(session: SessionContainer = Depends(verify_session())):
    await session.revoke_session() # This will delete the session from the db and from the frontend (cookies)
    return PlainTextResponse(content='success')
from supertokens_python.recipe.session.framework.flask import verify_session
from supertokens_python.recipe.session import SessionContainer
from flask import g

@app.route('/some_api', methods=['POST'])
@verify_session()
def some_api():
    session: SessionContainer = g.supertokens

    session.sync_revoke_session() # This will delete the session from the db and from the frontend (cookies)
    return 'success'
from typing import cast

from django.http import HttpRequest

from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.framework.django.asyncio import verify_session


@verify_session()
async def some_api(request: HttpRequest):
    session: SessionContainer = cast(SessionContainer, request.supertokens)  # Set by the session middleware.
    await session.revoke_session()

Direct session invalidation

To invalidate a session without relying on the intervention of a user you can create your own custom methods using the backend SDKs.

Revoke a specific session

import Session from "supertokens-node/recipe/session";

async function revokeSession(sessionHandle: string) {
  let revoked = await Session.revokeSession(sessionHandle);
}
import "github.com/supertokens/supertokens-golang/recipe/session"

func main() {
	sessionHandle := "someSessionHandle"
	revoked, err := session.RevokeSession(sessionHandle)
	if err != nil {
		// TODO: Handle error
		return
	}

	if revoked {
		// session was revoked
	} else {
		// session was not found
	}
}
from supertokens_python.recipe.session.asyncio import revoke_session

async def some_func():
    session_handle = "someSessionHandle"
    _ = await revoke_session(session_handle)
from supertokens_python.recipe.session.syncio import revoke_session

session_handle = "someSessionHandle"
revoked = revoke_session(session_handle)

You can fetch all the sessionHandles for a user using the getAllSessionHandlesForUser function

Revoke all sessions for a user

import express from "express";
import Session from "supertokens-node/recipe/session";

let app = express();

app.use("/revoke-all-user-sessions", async (req, res) => {
  let userId = req.body.userId;
  await Session.revokeAllSessionsForUser(userId);

  res.send("Success! All user sessions have been revoked");
});
import (
	"fmt"

	"github.com/supertokens/supertokens-golang/recipe/session"
)

func main() {
    tenantId := "public"
	revokedSessionHandles, err := session.RevokeAllSessionsForUser("userId", &tenantId)
	if err != nil {
		// TODO: Handle error
		return
	}

	// revokedSessionHandles is an array of revoked session handles.
	fmt.Println(revokedSessionHandles)
}
from supertokens_python.recipe.session.asyncio import revoke_all_sessions_for_user

async def some_func():
    user_id = "someUserId"
    revoked_session_handles = await revoke_all_sessions_for_user(user_id)

    print(revoked_session_handles) # revoked_session_handles is an array of revoked session handles.
from supertokens_python.recipe.session.syncio import revoke_all_sessions_for_user

user_id = "someUserId"
revoked_session_handles = revoke_all_sessions_for_user(user_id)

# revoked_session_handles is an array of revoked session handles.

See also

API reference

API schema and response details