Securing your API and frontend routes
#
Protecting APIs#
Requiring an active sessionFor your APIs that require a user to be logged in, use the verifySession
middleware
- NodeJS
- GoLang
- Python
- 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(), (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 { 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 ginfunc 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_sessionfrom supertokens_python.recipe.session import SessionContainerfrom 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_sessionfrom supertokens_python.recipe.session import SessionContainerfrom 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_sessionfrom django.http import HttpRequestfrom 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 authenticationFor authentication between microservices on your backend, checkout the microservice auth guide.
#
Protecting website routes- ReactJS
- Angular
- Vue
You can use the doesSessionExist
function to check if a session exists in all your routes.
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 wrap your components with the <SessionAuth>
react component. This will ensure that your component renders only if the user is logged in. If they are not logged in, the user will be redirected to the login page.
import React from "react";import { BrowserRouter, Routes, Route,} from "react-router-dom";import { SessionAuth } from "supertokens-auth-react/recipe/session";import MyDashboardComponent from "./dashboard";
class App extends React.Component { render() { return ( <BrowserRouter> <Routes> <Route path="/dashboard" element={ <SessionAuth> {/*Components that require to be protected by authentication*/} <MyDashboardComponent /> </SessionAuth> } /> </Routes> </BrowserRouter> ); }}
You can use the doesSessionExist
function to check if a session exists in all your routes.
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 }}
#
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