Skip to main content

Guide

Overview#

Integrating SuperTokens into a NestJS backend is a bit different than the quick setup guide shows. We will add a few things:

  • A module to house all authorization related code
  • A service to initialize the SDK
  • A middleware to add the authorization endpoints
  • A global error handler to pass SuperTokens related errors to the SDK
  • A guard to protect your API endpoints
  • A parameter decorator to access the session in your code

We will cover each of these in the following few sections. Then, you can do the rest of the customizations by following the "Common customizations" section.

Please look here to see how to get started with your NestJS backend.

1) Installing SuperTokens#

npm i -s supertokens-node

2) Adding a new module#

You can scaffold a module using the nest CLI by running this in the root folder of the application:

nest g module auth

The result should be a new auth folder with auth.module.ts in it. We should convert this into a dynamic module so we can set parts of the SuperTokens configuration in the App module. Centralizing settings like this can be helpful for things like using a separate connection URI for testing.

Add config type and injection token#

Add a config.ts file next into the auth folder. We will put the type and injection token for the SuperTokens config here.

import { AppInfo } from "supertokens-node/lib/build/types";
export const ConfigInjectionToken = "ConfigInjectionToken";
export type AuthModuleConfig = {  appInfo: AppInfo;  connectionURI: string;  apiKey?: string;}

Convert to a dynamic module#

We want to configure this module in the App module, so we add a static forRoot method and convert it into a dynamic module.

import {  MiddlewareConsumer,  Module,  NestModule,  DynamicModule,} from '@nestjs/common';
import { AuthMiddleware } from './auth.middleware';import { ConfigProviderToken, AuthModuleConfig } from './config.interface';
@Module({  providers: [],  exports: [],  controllers: [],})export class AuthModule implements NestModule {  configure(consumer: MiddlewareConsumer) {    consumer.apply(AuthMiddleware).forRoutes('*');  }
  static forRoot({ connectionURI, apiKey, appInfo }: AuthModuleConfig): DynamicModule {    return {      providers: [        {          useValue: {            appInfo,            connectionURI,            apiKey,          },          provide: ConfigProviderToken,        },      ],      exports: [],      imports: [],      module: AuthModule,    };  }}

Adding the module to the application#

Please fill the form below to see the code snippet (* = Required)
Your app's name:*
This is the name of your application
API Domain:*
This is the URL of your app's API domain, without any path.
Website Domain:*
This is the URL of your website, without any path.
Fill form to submit

3) Adding a service#

Please fill the form below to see the code snippet (* = Required)
API Domain:*
This is the URL of your app's API domain, without any path.
Website Domain:*
This is the URL of your website, without any path.
Fill form to submit

4) Exposing SuperTokens APIs using its middleware#

The middleware file#

You can scaffold the middleware by running nest g middleware auth auth in the application's root folder. The result should be in the auth module, called auth.middleware.ts. Next, we need to edit this to use the middleware from supertokens.

import { Injectable, NestMiddleware } from "@nestjs/common";import { middleware } from 'supertokens-node/framework/express';
@Injectable()export class AuthMiddleware implements NestMiddleware {  supertokensMiddleware: any;
  constructor() {    this.supertokensMiddleware = middleware();  }
  use(req: Request, res: any, next: () => void) {    return this.supertokensMiddleware(req, res, next);  }}

Registering the middleware#

We need to edit the module file to register the middleware. You can achieve this by implementing a configure method in the AuthModule class.

import { DynamicModule, MiddlewareConsumer, Module, NestModule } from "@nestjs/common";import { AuthMiddleware } from "./auth.middleware";...
export class AuthModule implements NestModule {  configure(consumer: MiddlewareConsumer) {    consumer.apply(AuthMiddleware).forRoutes('*');  }  ...}

5) Update CORS settings#

Please fill the form below to see the code snippet (* = Required)
Website Domain:*
This is the URL of your website, without any path.
Fill form to submit

6) Add the SuperTokens error handler#

We add the SuperTokens error handler through a NestJS exception filter.

Exception filter#

You can scaffold the exception filter using the CLI by: nest g filter auth auth. This will result in a new auth.filter.ts file next to the auth module. We need to edit this to add our error handler.

import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';import { Request, Response, NextFunction, ErrorRequestHandler } from 'express';
import { errorHandler } from 'supertokens-node/framework/express';import { Error } from 'supertokens-node';
@Catch(Error)export class SupertokensExceptionFilter implements ExceptionFilter {  handler: ErrorRequestHandler;
  constructor() {    this.handler = errorHandler();  }
  catch(exception: Error, host: ArgumentsHost) {    const ctx = host.switchToHttp();
    this.handler(      exception,      ctx.getRequest<Request>(),      ctx.getResponse<Response>(),      ctx.getNext<NextFunction>(),    );  }}

Registering the filter#

We need to add this filter as a global exception filter. You can do this in main.ts, right after the updated cors settings.

import { NestFactory } from '@nestjs/core';import { AppModule } from './app.module';
import supertokens from 'supertokens-node';import { SupertokensExceptionFilter } from './auth.filter';
async function bootstrap() {  const app = await NestFactory.create(AppModule);  app.enableCors({    origin: ['http://localhost:3000'],    allowedHeaders: ['content-type', ...supertokens.getAllCORSHeaders()],    credentials: true,  });
  app.useGlobalFilters(new SupertokensExceptionFilter());
  await app.listen(3000);}
bootstrap();

7) Add session verification guard#

Now that the library is set up, you can add a guard to protect your API. You can scaffold this nest g guard auth auth. This results in auth.guard.ts that we can edit to implement session verification.

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { verifySession } from 'supertokens-node/recipe/session/framework/express';
@Injectable()export class AuthGuard implements CanActivate {  async canActivate(context: ExecutionContext): Promise<boolean> {    const ctx = context.switchToHttp();
    let err = undefined;    await verifySession()(      ctx.getRequest(),      ctx.getResponse(),      (res) => {        err = res;      },    );
    if (err !== undefined) {      throw err;    }
    return true;  }}

8) Add a parameter decorator#

Now you can add a parameter decorator to access the already verified session in your APIs. You can generate an empty decorator by running nest g decorator session auth. Edit session.decorator.ts to return the session attached to the request:

import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const Session = createParamDecorator(  (data: unknown, ctx: ExecutionContext) => {    const request = ctx.switchToHttp().getRequest();    return request.session;  },);

9) Combine the decorator and the guard to authenticate users#

You can add a protected method into a controller (e.g.: App.controller.ts) that receives the verified session as a parameter by:

...import { AuthGuard } from './auth/auth.guard';import { Session } from './auth/session.decorator';...
@Controller()export class AppController {  ...  @Get('test')  @UseGuards(AuthGuard)  async getTest(@Session() session): Promise<string> {    // TODO: magic  }}

You should look at the Sessions section under Common Customizations to see how you can use the session object.

10) Setup the SuperTokens core#

Are you using https://try.supertokens.io as the connection URI in the init function?
YesNo
Refresh the page to undo your selection