---
title: Session Invalidation
description: >-
  Learn how to handle session expiry, implement sign out, and revoke sessions across different programming languages and
  frameworks.
sidebar:
  order: 30
---

## 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

:::info[Access token guidance]
This guide applies to scenarios involving **SuperTokens Session Access Tokens**.
:::

---

## 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.

:::note[You have to add your own redirection logic after the sign out call completes.]
:::


<UITypeSwitch />

<VariantContent storageKey="ui-type" value="prebuilt">

<CodeGroup group="frontend-prebuilt-ui">
<Tab title="Reactjs" value="reactjs">
```tsx
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>
  );
}
```
</Tab>
<Tab title="Angular" value="angular">
```tsx
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
}
```
</Tab>
</CodeGroup>

</VariantContent>

<VariantContent storageKey="ui-type" value="custom">



<CodeGroup group="frontend-custom-ui">
<Tab title="Web" value="web">
<DependentContent group="install-method" label="Installation method">
<ContentOption title="npm" value="npm">
```tsx
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
}
```
</ContentOption>
<ContentOption title="Script tag" value="script-tag">
```tsx check=false reason="Requires SDK globals from surrounding application"
async function logout() {
  await supertokensSession.signOut();
  window.location.href = "/auth"; // or redirect to wherever the login page is
}
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="Mobile" value="mobile">
<DependentContent group="mobile-frameworks" label="Mobile framework">
<ContentOption title="ReactNative" value="reactnative">
```tsx
import SuperTokens from "supertokens-react-native";

async function logout() {
  await SuperTokens.signOut();
  // navigate to the login screen..
}
```
</ContentOption>
<ContentOption title="Android" value="android">
```kotlin
import android.app.Application
import com.supertokens.session.SuperTokens

class MainApplication: Application() {
    fun logout() {
        SuperTokens.signOut(this);
        // navigate to the login screen..
    }
}
```
</ContentOption>
<ContentOption title="iOS" value="ios">
```swift
import UIKit
import SuperTokensIOS

fileprivate class ViewController: UIViewController {
  func signOut() {
    SuperTokens.signOut(completionHandler: {
        error in

        if error != nil {
            // handle error
        } else {
            // Signed out successfully
        }
    })
  }
}
```
</ContentOption>
<ContentOption title="Flutter" value="flutter">
```dart
import 'package:supertokens_flutter/supertokens.dart';

Future<void> signOut() async {
    await SuperTokens.signOut(
      completionHandler: (error) => {
        // Handle error if any
      }
    );
}
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>



</VariantContent>

### Expose a backend sign out method

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

<DependentContent passive group="backend-language">
<ContentOption title="Node.js" value="nodejs">
<DependentContent passive group="node-frameworks">
<ContentOption title="Next.js" value="nextjs">
<NextjsRouterTypeSelect />
</ContentOption>
</DependentContent>
</ContentOption>
</DependentContent>

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
<DependentContent group="node-frameworks" label="Node.js framework">
<ContentOption title="Express" value="express">
```tsx
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");
});
```
</ContentOption>
<ContentOption title="Hapi" value="hapi">
```tsx
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);
  },
});
```
</ContentOption>
<ContentOption title="Fastify" value="fastify">
```tsx
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");
  },
);
```
</ContentOption>
<ContentOption title="Aws Lambda" value="aws-lambda">
```tsx
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);
```
</ContentOption>
<ContentOption title="Koa" value="koa">
```tsx
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";
});
```
</ContentOption>
<ContentOption title="LoopBack" value="loopback">
```tsx
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";
  }
}
```
</ContentOption>
<ContentOption title="Next.js" value="nextjs">
<ConditionalContent propertyName="nextjsRouterType" condition="pages-router">

```tsx
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 someapi(req: SessionRequest, res: any) {
  await superTokensNextWrapper(
    async (next) => {
      await verifySession()(req, res, next);
    },
    req,
    res,
  );
  // This will delete the session from the db and from the frontend (cookies)
  await req.session!.revokeSession();
  res.send("Success! User session revoked");
}
```

</ConditionalContent>
</ContentOption>
<ContentOption title="Nestjs" value="nestjs">
```ts check=false reason="Requires surrounding framework application context"
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";
  }
}
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="Go" value="go">
```go
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
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-frameworks" label="Python framework">
<ContentOption title="FastAPI" value="fastapi">
```python
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')
```
</ContentOption>
<ContentOption title="Flask" value="flask">
```python check=false reason="Requires surrounding framework application context"
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'
```
</ContentOption>
<ContentOption title="Django" value="django">
```python check=false reason="Requires surrounding async application context"
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()
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

<CodeGroup passive group="backend-language">
<Tab title="Node.js" value="nodejs">
<DependentContent group="node-frameworks" label="Node.js framework">
<ContentOption title="Next.js" value="nextjs">
<ConditionalContent propertyName="nextjsRouterType" condition="app-router">

```tsx check=false reason="Requires surrounding framework application context"
import { NextResponse, NextRequest } from "next/server";
import SuperTokens from "supertokens-node";
import { withSession } from "supertokens-node/nextjs";
import { backendConfig } from "@/app/config/backend";

SuperTokens.init(backendConfig());

export function POST(request: NextRequest) {
  return withSession(request, async (err, session) => {
    if (err) {
      return NextResponse.json(err, { status: 500 });
    }
    // This will delete the session from the db and from the frontend (cookies)
    await session!.revokeSession();
    return NextResponse.json({ message: "Success! User session revoked" });
  });
}
```

</ConditionalContent>
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

:::info[Tip]

If you are using the pre-built UI and the `<SessionAuth>` component, you can set custom post-logout logic with the `onSessionExpired` prop.
The handler gets called if:
- The backend has revoked the session, but not the frontend.
- The user has been inactive for too long and their refresh token has expired.

```tsx check=false reason="Requires surrounding framework application context"
import React from "react";
import { SessionAuth } from "supertokens-auth-react/recipe/session";
import MyComponent from "./myComponent";

const App = () => {
  return (
    <SessionAuth
      onSessionExpired={() => {
        /* ... */
      }}
    >
      <MyComponent />
    </SessionAuth>
  );
};
```
:::

---

## 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.

:::warning[This method of revoking a session only deletes the session from the database and not from the frontend.]
This implies that the user can still access protected endpoints while their access token is alive.
If you want to instantly logout the user in this mode, you should [enable access token blacklisting](/post-authentication/session-management/advanced-workflows/access-token-blacklisting).
:::

### Revoke a specific session

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import Session from "supertokens-node/recipe/session";

async function revokeSession(sessionHandle: string) {
  let revoked = await Session.revokeSession(sessionHandle);
}
```
</Tab>
<Tab title="Go" value="go">
```go
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
	}
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.session.asyncio import revoke_session

async def some_func():
    session_handle = "someSessionHandle"
    _ = await revoke_session(session_handle)
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.session.syncio import revoke_session

session_handle = "someSessionHandle"
revoked = revoke_session(session_handle)
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

You can fetch all the `sessionHandle`s for a user using the [`getAllSessionHandlesForUser` function](/post-authentication/session-management/access-session-data#fetch-all-user-sessions)

### Revoke all sessions for a user

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
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");
});
```
</Tab>
<Tab title="Go" value="go">
```go
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)
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
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.
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
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.
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

:::info[Multi Tenancy]
By default, revokeAllSessionsForUser deletes all the sessions for the user across all the tenants. If you want to delete the sessions for a user in a specific tenant, you can pass the tenant ID as a parameter to the function call.
:::

---

## See also

<CardGroup cols={3}>
  <Card title="Access session data" href="/post-authentication/session-management/access-session-data" />
  <Card title="Security" href="/post-authentication/session-management/security" />
  <Card title="Access token blacklisting" href="/post-authentication/session-management/advanced-workflows/access-token-blacklisting" />
  <Card title="Post login redirect" href="/post-authentication/post-login-redirect" />
  <Card title="Session migration" href="/migration/session-migration" />
</CardGroup>
