Skip to content

Commit

Permalink
Merge pull request #798 from supertokens/fix/nest-docs
Browse files Browse the repository at this point in the history
fix: Update NestJS AuthGuard to use getSession
  • Loading branch information
rishabhpoddar authored May 30, 2024
2 parents a0d811d + 89b1421 commit 7fadff1
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 170 deletions.
60 changes: 26 additions & 34 deletions v2/emailpassword/nestjs/guide.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export class AuthModule implements NestModule {
}
```
In the provided code sample, we convert this to a [dynamic module](https://docs.nestjs.com/modules#dynamic-modules) so we can configure parts of the SuperTokens setup within the App module. This approach allows for centralized configuration, which can be particularly beneficial when managing settings such as using distinct connection URIs for different environments, such as testing or production.
In the provided code sample, we convert `AuthModule` to a [dynamic module](https://docs.nestjs.com/modules#dynamic-modules) so we can configure parts of the SuperTokens setup within the App module. This approach allows for centralized configuration, which can be particularly beneficial when managing settings such as using distinct connection URIs for different environments, such as testing or production.
:::info
The middleware is registered using the `configure` method in the `AuthModule` class.
Expand Down Expand Up @@ -290,9 +290,6 @@ export class SupertokensExceptionFilter implements ExceptionFilter {
const ctx = host.switchToHttp();

const resp = ctx.getResponse<Response>();
if (resp.headersSent) {
return;
}

this.handler(
exception,
Expand All @@ -308,6 +305,9 @@ export class SupertokensExceptionFilter implements ExceptionFilter {
We need to add this filter as a global exception filter. You can do this in `main.ts`, right after the updated CORS settings.
<AppInfoForm
askForWebsiteDomain={true}>
```ts title="./src/main.ts"
import { NestFactory } from '@nestjs/core';
// @ts-ignore
Expand All @@ -320,7 +320,7 @@ import { SupertokensExceptionFilter } from './auth/auth.filter';
async function bootstrap() {
const app = await NestFactory.create(AuthModule);
app.enableCors({
origin: ['http://localhost:3001'], // TODO: URL of the website domain
origin: ['^{form_websiteDomain}'],
allowedHeaders: ['content-type', ...supertokens.getAllCORSHeaders()],
credentials: true,
});
Expand All @@ -334,6 +334,7 @@ async function bootstrap() {

bootstrap();
```
</AppInfoForm>
## Add a session verification guard
Expand All @@ -343,40 +344,25 @@ In the newly created `auth.guard.ts` file, implement session verification:
```ts title="./src/auth/auth.guard.ts"
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Error as STError } from "supertokens-node";

import { verifySession } from 'supertokens-node/recipe/session/framework/express';
import { VerifySessionOptions } from 'supertokens-node/recipe/session';
import { getSession, VerifySessionOptions } from 'supertokens-node/recipe/session';

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private readonly verifyOptions?: VerifySessionOptions) {}
constructor(private readonly getSessionOptions?: VerifySessionOptions) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
public async canActivate(context: ExecutionContext): Promise<boolean> {
const ctx = context.switchToHttp();

let err = undefined;
const req = ctx.getRequest();
const resp = ctx.getResponse();
// You can create an optional version of this by passing {sessionRequired: false} to verifySession
await verifySession(this.verifyOptions)(
ctx.getRequest(),
resp,
(res: any) => {
err = res;
},
);

if (resp.headersSent) {
throw new STError({
message: "RESPONSE_SENT",
type: "RESPONSE_SENT",
});
}

if (err) {
throw err;
}
// If the session doesn't exist and {sessionRequired: true} is passed to the AuthGuard constructor (default is true),
// getSession will throw an error, that will be handled by the exception filter, returning a 401 response.

// To avoid an error when the session doesn't exist, pass {sessionRequired: false} to the AuthGuard constructor.
// In this case, req.session will be undefined if the session doesn't exist.
const session = await getSession(req, resp, this.getSessionOptions);
req.session = session;
return true;
}
}
Expand Down Expand Up @@ -414,11 +400,17 @@ import { Session } from './auth/session/session.decorator';
@Controller()
export class AppController {
// ...
@Get('test')
// Test endpoint for session verification; not part of the Supertokens setup.
@Get('/test')
@UseGuards(new AuthGuard())
async getTest(@Session() session: SessionContainer): Promise<string> {
// TODO: magic
return "magic";
getSessionInfo(
@Session() session: SessionContainer,
): Record<string, unknown> {
return {
sessionHandle: session.getHandle(),
userId: session.getUserId(),
accessTokenPayload: session.getAccessTokenPayload(),
};
}
}
```
Expand Down
60 changes: 26 additions & 34 deletions v2/passwordless/nestjs/guide.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export class AuthModule implements NestModule {
}
```
In the provided code sample, we convert this to a [dynamic module](https://docs.nestjs.com/modules#dynamic-modules) so we can configure parts of the SuperTokens setup within the App module. This approach allows for centralized configuration, which can be particularly beneficial when managing settings such as using distinct connection URIs for different environments, such as testing or production.
In the provided code sample, we convert `AuthModule` to a [dynamic module](https://docs.nestjs.com/modules#dynamic-modules) so we can configure parts of the SuperTokens setup within the App module. This approach allows for centralized configuration, which can be particularly beneficial when managing settings such as using distinct connection URIs for different environments, such as testing or production.
:::info
The middleware is registered using the `configure` method in the `AuthModule` class.
Expand Down Expand Up @@ -309,9 +309,6 @@ export class SupertokensExceptionFilter implements ExceptionFilter {
const ctx = host.switchToHttp();

const resp = ctx.getResponse<Response>();
if (resp.headersSent) {
return;
}

this.handler(
exception,
Expand All @@ -327,6 +324,9 @@ export class SupertokensExceptionFilter implements ExceptionFilter {
We need to add this filter as a global exception filter. You can do this in `main.ts`, right after the updated CORS settings.
<AppInfoForm
askForWebsiteDomain={true}>
```ts title="./src/main.ts"
import { NestFactory } from '@nestjs/core';
// @ts-ignore
Expand All @@ -339,7 +339,7 @@ import { SupertokensExceptionFilter } from './auth/auth.filter';
async function bootstrap() {
const app = await NestFactory.create(AuthModule);
app.enableCors({
origin: ['http://localhost:3001'], // TODO: URL of the website domain
origin: ['^{form_websiteDomain}'],
allowedHeaders: ['content-type', ...supertokens.getAllCORSHeaders()],
credentials: true,
});
Expand All @@ -353,6 +353,7 @@ async function bootstrap() {

bootstrap();
```
</AppInfoForm>
## Add a session verification guard
Expand All @@ -362,40 +363,25 @@ In the newly created `auth.guard.ts` file, implement session verification:
```ts title="./src/auth/auth.guard.ts"
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Error as STError } from "supertokens-node";

import { verifySession } from 'supertokens-node/recipe/session/framework/express';
import { VerifySessionOptions } from 'supertokens-node/recipe/session';
import { getSession, VerifySessionOptions } from 'supertokens-node/recipe/session';

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private readonly verifyOptions?: VerifySessionOptions) {}
constructor(private readonly getSessionOptions?: VerifySessionOptions) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
public async canActivate(context: ExecutionContext): Promise<boolean> {
const ctx = context.switchToHttp();

let err = undefined;
const req = ctx.getRequest();
const resp = ctx.getResponse();
// You can create an optional version of this by passing {sessionRequired: false} to verifySession
await verifySession(this.verifyOptions)(
ctx.getRequest(),
resp,
(res: any) => {
err = res;
},
);

if (resp.headersSent) {
throw new STError({
message: "RESPONSE_SENT",
type: "RESPONSE_SENT",
});
}

if (err) {
throw err;
}
// If the session doesn't exist and {sessionRequired: true} is passed to the AuthGuard constructor (default is true),
// getSession will throw an error, that will be handled by the exception filter, returning a 401 response.

// To avoid an error when the session doesn't exist, pass {sessionRequired: false} to the AuthGuard constructor.
// In this case, req.session will be undefined if the session doesn't exist.
const session = await getSession(req, resp, this.getSessionOptions);
req.session = session;
return true;
}
}
Expand Down Expand Up @@ -433,11 +419,17 @@ import { Session } from './auth/session/session.decorator';
@Controller()
export class AppController {
// ...
@Get('test')
// Test endpoint for session verification; not part of the Supertokens setup.
@Get('/test')
@UseGuards(new AuthGuard())
async getTest(@Session() session: SessionContainer): Promise<string> {
// TODO: magic
return "magic";
getSessionInfo(
@Session() session: SessionContainer,
): Record<string, unknown> {
return {
sessionHandle: session.getHandle(),
userId: session.getUserId(),
accessTokenPayload: session.getAccessTokenPayload(),
};
}
}
```
Expand Down
60 changes: 26 additions & 34 deletions v2/thirdparty/nestjs/guide.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export class AuthModule implements NestModule {
}
```
In the provided code sample, we convert this to a [dynamic module](https://docs.nestjs.com/modules#dynamic-modules) so we can configure parts of the SuperTokens setup within the App module. This approach allows for centralized configuration, which can be particularly beneficial when managing settings such as using distinct connection URIs for different environments, such as testing or production.
In the provided code sample, we convert `AuthModule` to a [dynamic module](https://docs.nestjs.com/modules#dynamic-modules) so we can configure parts of the SuperTokens setup within the App module. This approach allows for centralized configuration, which can be particularly beneficial when managing settings such as using distinct connection URIs for different environments, such as testing or production.
:::info
The middleware is registered using the `configure` method in the `AuthModule` class.
Expand Down Expand Up @@ -367,9 +367,6 @@ export class SupertokensExceptionFilter implements ExceptionFilter {
const ctx = host.switchToHttp();
const resp = ctx.getResponse<Response>();
if (resp.headersSent) {
return;
}
this.handler(
exception,
Expand All @@ -385,6 +382,9 @@ export class SupertokensExceptionFilter implements ExceptionFilter {

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

<AppInfoForm
askForWebsiteDomain={true}>

```ts title="./src/main.ts"
import { NestFactory } from '@nestjs/core';
// @ts-ignore
Expand All @@ -397,7 +397,7 @@ import { SupertokensExceptionFilter } from './auth/auth.filter';
async function bootstrap() {
const app = await NestFactory.create(AuthModule);
app.enableCors({
origin: ['http://localhost:3001'], // TODO: URL of the website domain
origin: ['^{form_websiteDomain}'],
allowedHeaders: ['content-type', ...supertokens.getAllCORSHeaders()],
credentials: true,
});
Expand All @@ -411,6 +411,7 @@ async function bootstrap() {

bootstrap();
```
</AppInfoForm>

## Add a session verification guard

Expand All @@ -420,40 +421,25 @@ In the newly created `auth.guard.ts` file, implement session verification:

```ts title="./src/auth/auth.guard.ts"
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Error as STError } from "supertokens-node";
import { verifySession } from 'supertokens-node/recipe/session/framework/express';
import { VerifySessionOptions } from 'supertokens-node/recipe/session';
import { getSession, VerifySessionOptions } from 'supertokens-node/recipe/session';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private readonly verifyOptions?: VerifySessionOptions) {}
constructor(private readonly getSessionOptions?: VerifySessionOptions) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
public async canActivate(context: ExecutionContext): Promise<boolean> {
const ctx = context.switchToHttp();
let err = undefined;
const req = ctx.getRequest();
const resp = ctx.getResponse();
// You can create an optional version of this by passing {sessionRequired: false} to verifySession
await verifySession(this.verifyOptions)(
ctx.getRequest(),
resp,
(res: any) => {
err = res;
},
);
if (resp.headersSent) {
throw new STError({
message: "RESPONSE_SENT",
type: "RESPONSE_SENT",
});
}
if (err) {
throw err;
}
// If the session doesn't exist and {sessionRequired: true} is passed to the AuthGuard constructor (default is true),
// getSession will throw an error, that will be handled by the exception filter, returning a 401 response.
// To avoid an error when the session doesn't exist, pass {sessionRequired: false} to the AuthGuard constructor.
// In this case, req.session will be undefined if the session doesn't exist.
const session = await getSession(req, resp, this.getSessionOptions);
req.session = session;
return true;
}
}
Expand Down Expand Up @@ -491,11 +477,17 @@ import { Session } from './auth/session/session.decorator';
@Controller()
export class AppController {
// ...
@Get('test')
// Test endpoint for session verification; not part of the Supertokens setup.
@Get('/test')
@UseGuards(new AuthGuard())
async getTest(@Session() session: SessionContainer): Promise<string> {
// TODO: magic
return "magic";
getSessionInfo(
@Session() session: SessionContainer,
): Record<string, unknown> {
return {
sessionHandle: session.getHandle(),
userId: session.getUserId(),
accessTokenPayload: session.getAccessTokenPayload(),
};
}
}
```
Expand Down
Loading

0 comments on commit 7fadff1

Please sign in to comment.