Securing your API and frontend routes
Protecting APIs#
Requiring an active session#
For your APIs that require a user to be logged in, use the verifySession middleware
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
- Express
- Hapi
- Fastify
- Koa
- Loopback
- AWS Lambda / Netlify
- Next.js (Pages Dir)
- Next.js (App Dir)
- 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(), (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()
            },
        ],
    },
    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(),
}, (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);
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(), (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())
    @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()(req, res, next);
        },
        req,
        res
    )
    let userId = req.session!.getUserId();
    //....
}
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 });
        }
        const userId = session!.getUserId();
        //....
        return NextResponse.json({});
    });
}
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()) // 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"
)
func main() {
    _ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
        // Wrap the API handler in session.VerifySession
        session.VerifySession(nil, 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
    router.POST("/likecomment", verifySession(nil), 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"
)
func main() {
    r := chi.NewRouter()
    // Wrap the API handler in session.VerifySession
    r.Post("/likecomment", session.VerifySession(nil, 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"
)
func main() {
    router := mux.NewRouter()
    // Wrap the API handler in session.VerifySession
    router.HandleFunc("/likecomment", session.VerifySession(nil, 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())):
    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()
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()
async def like_comment(request: HttpRequest):
    session: SessionContainer = request.supertokens 
    user_id = session.get_user_id()
    
    print(user_id)
The verifySession function returns a 401 to the frontend if a session doesn't exist, or if the access token has expired, in which case, our frontend SDK automatically refreshes the session.
In case of successful session verification, you get access to a session object using which you can get the user's ID, or manipulate the session information.
Microservice authentication#
For authentication between microservices on your backend, checkout the microservice auth guide.
Protecting frontend routes#
- Web
- Mobile
- Via NPM
- Via Script Tag
You can use the doesSessionExist function to check if a session exists.
import Session from 'supertokens-web-js/recipe/session';
async function doesSessionExist() {
    if (await Session.doesSessionExist()) {
        // user is logged in
    } else {
        // user has not logged in yet
    }
}
You can use the doesSessionExist function to check if a session exists.
async function doesSessionExist() {
    if (await Session.doesSessionExist()) {
        // user is logged in
    } else {
        // user has not logged in yet
    }
}
- React Native
- Android
- iOS
- Flutter
You can use the doesSessionExist function to check if a session exists.
import SuperTokens from 'supertokens-react-native';
async function doesSessionExist() {
    if (await SuperTokens.doesSessionExist()) {
        // user is logged in
    } else {
        // user has not logged in yet
    }
}
You can use the doesSessionExist function to check if a session exists.
import android.app.Application
import com.supertokens.session.SuperTokens
class MainApplication: Application() {
    fun doesSessionExist() {
        if (SuperTokens.doesSessionExist(this.applicationContext)) {
            // user is logged in
        } else {
            // user has not logged in yet
        }
    }
}
You can use the doesSessionExist function to check if a session exists.
import UIKit
import SuperTokensIOS
class ViewController: UIViewController {
    func doesSessionExist() {
        if SuperTokens.doesSessionExist() {
            // User is logged in
        } else {
            // User is not logged in
        }
    }
}
You can use the doesSessionExist function to check if a session exists.
import 'package:supertokens_flutter/supertokens.dart';
Future<bool> doesSessionExist() async {
    return await SuperTokens.doesSessionExist();
}
See also#
- Optional sessions for APIs and the frontend
- Verifying session without using a middleware
- Session claim validation for APIs and the frontend
- Changing session lifetime
- Sharing session across sub domains