This package contains a set of utilities commonly used for authentication purposes in the MultiversX Microservice ecosystem.
The package relies on @multiversx/sdk-native-auth-server for validating access tokens signed by MultiversX wallets.
sdk-nestjs-auth
is delivered via npm and it can be installed as follows:
npm install @multiversx/sdk-nestjs-auth
This package validates a payload signed by a MultiversX wallet. You can use the MultiversX Utils website to get a token you can use for testing.
- Navigate to https://utils.multiversx.com/auth and choose the desired network from the select located in the upper right corner of the page
- Click the Generate button
- Select a wallet you prefer to use from the modal dialog, and give it access to the page
- Done! You can now copy the token and use it as a Bearer token in your requests.
To use it in your requests, you need to have an Authorization
header with the value :
Bearer <your_token_goes_here>
.
You also need to add an origin
header with the value https://utils.multiversx.com
.
Note: these steps are only needed while testing. In production, a frontend application will handle token generation
The package provides a series of NestJS Guards that can be used for easy authorization on endpoints in your application.
It also provides some NestJS Decorators that expose the decoded information found in the access token.
The authentication guards need 2 parameters on instantiation.
The fist parameter needs to be an instance of a class implementing the MxnestConfigService
interface.
The second one, needs to be an instance of a Caching service
import { Injectable } from "@nestjs/common";
import { ApiConfigService } from "./api.config.service";
import { MxnestConfigService } from "@multiversx/sdk-nestjs-common";
@Injectable()
export class SdkNestjsConfigServiceImpl implements MxnestConfigService {
constructor(
private readonly apiConfigService: ApiConfigService,
) { }
getSecurityAdmins(): string[] {
return this.apiConfigService.getSecurityAdmins();
}
getJwtSecret(): string {
return this.apiConfigService.getJwtSecret();
}
getApiUrl(): string {
return this.apiConfigService.getApiUrl();
}
getNativeAuthMaxExpirySeconds(): number {
return this.apiConfigService.getNativeAuthMaxExpirySeconds();
}
getNativeAuthAcceptedOrigins(): string[] {
return this.apiConfigService.getNativeAuthAcceptedOrigins();
}
}
You can register it as a provider, and the DI mechanism of NestJS will handle instantiation for you.
import { Module } from '@nestjs/common';
import { MXNEST_CONFIG_SERVICE } from "@multiversx/sdk-nestjs-common";
@Module({
providers: [
{
provide: MXNEST_CONFIG_SERVICE,
useClass: SdkNestjsConfigServiceImpl,
},
],
})
export class AppModule {}
NestJS guards can be controller-scoped, method-scoped, or global-scoped. Setting up a guard from the package is done through the @UseGuards
decorator from the @nestjs/common
package.
NativeAuthGuard
performs validation of the block hash, verifies its validity, as well as origin verification on the access token.
import { NativeAuthGuard } from "@multiversx/sdk-nestjs-auth";
@Controller('projects')
@UseGuards(NativeAuthGuard)
export class ProjectsController {
// your methods...
}
In the example above the NativeAuthGuard
is controller-scoped. This means that all of the methods from ProjectsController
will be protected by the guard.
import { NativeAuthGuard } from "@multiversx/sdk-nestjs-auth";
@Controller('projects')
export class ProjectsController {
@Get()
async getAll() {
return this.projectsService.getAll();
}
@Post()
@UseGuards(NativeAuthGuard)
async createProject(@Body() createProjectDto: CreateProjectDto) {
return this.projectsService.create(createProjectDto);
}
}
In this case, the guard is method-scoped. Only createProject
benefits from the native auth checks.
NativeAuthAdminGuard
allows only specific addresses to be authenticated. The addresses are defined in the config file and are passed to the guard via the MxnestConfigService.
This guard cannot be used by itself. It always has to be paired with a NativeAuthGuard
import { NativeAuthGuard, NativeAuthAdminGuard } from "@multiversx/sdk-nestjs-auth";
@Controller('admin')
@UseGuards(NativeAuthGuard, NativeAuthAdminGuard)
export class AdminController {
// your methods...
}
JwtAuthenticateGuard
performs validation of a traditional JSON web token. The usage is exactly the same as for the native auth guards.
import { JwtAuthenticateGuard } from "@multiversx/sdk-nestjs-auth";
@Controller('users')
@UseGuards(JwtAuthenticateGuard)
export class UsersController {
// your methods...
}
JwtAdminGuard
relies on the same mechanism, only specific addresses can be authenticated. The addresses are defined in the config file and are passed to the guard via the MxnestConfigService.
There is one caveat: when creating the JWT, the client must include an address
field in the payload, before signing it.
import { JwtAuthenticateGuard, JwtAdminGuard } from "@multiversx/sdk-nestjs-auth";
@Controller('admin')
@UseGuards(JwtAuthenticateGuard, JwtAdminGuard)
export class AdminController {
// your methods...
}
JwtOrNativeAuthGuard
guard will authorize requests containing either JWT or a native auth access token. The package will first look for a valid JWT. If that fails, it will look for a valid native auth access token.
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new NativeAuthGuard(new SdkNestjsConfigServiceImpl(apiConfigService), cachingService));
The package exposes 3 decorators : NativeAuth
, Jwt
and NoAuth
The NativeAuth
decorator accepts a single parameter. In can be one of the following values :
-
issued
- block timestamp -
expires
- expiration time -
address
- address that signed the access token -
origin
- URL of the page that generated the token -
extraInfo
- optional arbitrary data
Below is an example showing how to use the decorator to extract the signers address :
import { NativeAuthGuard, NativeAuth } from "@multiversx/sdk-nestjs-auth";
import { Controller, Get, UseGuards } from "@nestjs/common";
@Controller()
export class AuthController {
@Get("/auth")
@UseGuards(NativeAuthGuard)
authorize(@NativeAuth('address') address: string): string {
console.log(`Access granted for address ${address}`);
return address;
}
}
The Jwt
decorator works just like NativeAuth
. The fields accessible inside it are dependent on the client that created the token, and are out of scope for this documentation.
The NoAuth
decorator can be used to skip authorization on a specific method. This is useful when a guard is scoped globally or at the controller level.
import { NoAuth } from "@multiversx/sdk-nestjs-auth";
import { Controller, Get, UseGuards } from "@nestjs/common";
@Controller()
export class PublicController {
@NoAuth()
@Get("/public-posts")
listPosts() {
// ....
}
}