Rockets NestJS JWT
A flexible JWT utilities module for signing and validating tokens.
This module extends/wraps the @nestjs/jwt (opens in a new tab) module.
Project
(opens in a new tab)
(opens in a new tab)
(opens in a new tab)
(opens in a new tab)
(opens in a new tab)
JWT Module Documentation
Project
(opens in a new tab)
(opens in a new tab)
(opens in a new tab)
(opens in a new tab)
(opens in a new tab)
Table of Contents
Tutorials
Introduction
Overview of the Library
This module is designed to manage JWT authentication processes within a NestJS application. It includes services for issuing JWTs, validating user credentials, and verifying tokens. The services handle the generation of access and refresh tokens, ensure users are active and meet authentication criteria, and perform token validity checks, including additional validations if necessary. This comprehensive approach ensures secure user authentication and efficient token management.
Purpose and Key Features
- Secure Token Management: Provides robust mechanisms for issuing and managing access and refresh tokens, ensuring secure and efficient token lifecycle management.
- Abstract User Validation Service: Offers an abstract service to validate user credentials and check user activity status, ensuring that only eligible users can authenticate. This abstract nature requires implementations to define specific validation logic, allowing flexibility across different user models and authentication requirements.
- Token Verification: Includes capabilities to verify the authenticity and validity of tokens, with support for additional custom validations to meet specific security requirements.
- Customizable and Extensible: Designed to be flexible, allowing customization of token generation, user validation, and token verification processes to suit different application needs.
- Integration with NestJS Ecosystem: Seamlessly integrates with other NestJS modules and services, leveraging the framework's features for enhanced functionality and performance.
Installation
To get started, install the JwtModule
package:
sh-begin yarn add @concepta/nestjs-jwt sh-end
Basic Setup
To set up the JwtModule
, follow the basic setup tutorial in the
nestjs-authentication README (opens in a new tab).
Creating custom jwtIssueService
Here we will cover how to override the default services in JwtModule
.
For example, to override the JwtIssueService
, follow the steps below:
- Create a custom implementation of
JwtIssueService
:
import { Injectable } from '@nestjs/common';
import { JwtIssueServiceInterface } from './interfaces/jwt-issue-service.interface';
import { JwtSignService } from './jwt-sign.service';
@Injectable()
export class CustomJwtIssueService implements JwtIssueServiceInterface {
constructor(private readonly jwtSignService: JwtSignService) {}
async accessToken(...args: Parameters<JwtIssueServiceInterface['accessToken']>) {
return this.jwtSignService.signAsync('access', ...args);
}
async refreshToken(...args: Parameters<JwtIssueServiceInterface['refreshToken']>) {
return this.jwtSignService.signAsync('refresh', ...args);
}
}
- Provide the custom implementation in your module configuration:
import { Module } from '@nestjs/common';
import { JwtModule } from '@concepta/nestjs-jwt';
import { CustomJwtIssueService } from './custom-jwt-issue.service';
@Module({
imports: [
JwtModule.forRoot({
jwtIssueService: CustomJwtIssueService,
settings: {
access: {
secret: 'your-secret-key',
signOptions: { expiresIn: '60s' },
},
},
}),
],
providers: [CustomJwtIssueService],
})
export class AppModule {}
This example shows how to customize the JwtIssueService
with a custom
implementation. Similar steps can be followed to override other services in
JwtModule
.
environment variables
Configurations available via environment.
Variable | Type | Default | |
---|---|---|---|
JWT_MODULE_ACCESS_SECRET | <string | Buffer> | randomUUID() * see note | Access token secret |
JWT_MODULE_ACCESS_EXPIRES_IN | <string | number> | '1h' | Access token expiration length |
JWT_MODULE_REFRESH_SECRET | <string | Buffer> | copied from access secret | Refresh token secret |
JWT_MODULE_REFRESH_EXPIRES_IN | <string | number> | '1y' | Refresh token expiration length |
* For security reasons, a random UUID will only be generated for the default secret when
NODE_ENV !== 'production'
.
How to Guides
1. How to Set Up JwtModule with forRoot
To set up the JwtModule
, follow these steps:
import { Module } from '@nestjs/common';
import { JwtModule } from '@concepta/nestjs-jwt';
@Module({
imports: [
JwtModule.forRoot({}),
],
})
export class AppModule {}
This setup configures the JwtModule
with global settings and integrates the
JwtModule
for JWT-based authentication.
2. How to Configure JwtModule Settings
The JwtModule
provides several configurable settings to customize its
behavior. Each setting can be defined in the module configuration and will
create default services to be used in other modules.
Settings Example
Here is an example of how to configure each property of the settings:
import { Module } from '@nestjs/common';
import { JwtModule } from '@concepta/nestjs-jwt';
@Module({
imports: [
JwtModule.forRoot({
settings: {
access: {
secret: 'your-secret-key',
signOptions: { expiresIn: '60s' },
},
},
}),
],
})
export class AppModule {}
3. Overriding Defaults
To override the default services, you can provide custom implementations for any of the services.
JwtAccessService
@Injectable()
import { JwtService, JwtSignOptions } from '@nestjs/jwt';
class CustomJwtAccessService extends JwtService {
sign(_payload: string, _options?: JwtSignOptions): string {
return 'foo';
}
}
jwtRefreshService
@Injectable()
import { JwtService, JwtSignOptions } from '@nestjs/jwt';
class CustomRefreshJwtAccessService extends JwtService {
sign(_payload: string, _options?: JwtSignOptions): string {
return 'foo';
}
}
JwtIssueService
import { Injectable } from '@nestjs/common';
import { JwtIssueServiceInterface } from './interfaces/jwt-issue-service.interface';
import { JwtSignService } from './jwt-sign.service';
@Injectable()
export class CustomJwtIssueService implements JwtIssueServiceInterface {
constructor(private readonly jwtSignService: JwtSignService) {}
async accessToken(...args: Parameters<JwtIssueServiceInterface['accessToken']>) {
// Custom implementation
return this.jwtSignService.signAsync('access', ...args);
}
async refreshToken(...args: Parameters<JwtIssueServiceInterface['refreshToken']>) {
// Custom implementation
return this.jwtSignService.signAsync('refresh', ...args);
}
}
JwtVerifyService.
import { Injectable } from '@nestjs/common';
import { JwtVerifyServiceInterface } from './interfaces/jwt-verify-service.interface';
import { JwtSignService } from './jwt-sign.service';
@Injectable()
export class CustomJwtVerifyService implements JwtVerifyServiceInterface {
constructor(private readonly jwtSignService: JwtSignService) {}
async accessToken(...args: Parameters<JwtVerifyServiceInterface['accessToken']>) {
// Custom implementation
return this.jwtSignService.verifyAsync('access', ...args);
}
async refreshToken(...args: Parameters<JwtVerifyServiceInterface['refreshToken']>) {
// Custom implementation
return this.jwtSignService.verifyAsync('refresh', ...args);
}
}
JwtSignService
import { Inject, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { JwtSignServiceInterface } from '../interfaces/jwt-sign-service.interface';
import {
JWT_MODULE_JWT_ACCESS_SERVICE_TOKEN,
JWT_MODULE_JWT_REFRESH_SERVICE_TOKEN,
} from '../jwt.constants';
import { JwtTokenType } from '../jwt.types';
@Injectable()
export class CustomJwtSignService implements JwtSignServiceInterface {
constructor(
@Inject(JWT_MODULE_JWT_ACCESS_SERVICE_TOKEN)
protected readonly jwtAccessService: JwtService,
@Inject(JWT_MODULE_JWT_REFRESH_SERVICE_TOKEN)
protected readonly jwtRefreshService: JwtService,
) {}
async signAsync(
tokenType: JwtTokenType,
...rest: Parameters<JwtService['signAsync']>
) {
return this.service(tokenType).signAsync(...rest);
}
async verifyAsync(
tokenType: JwtTokenType,
...rest: Parameters<JwtService['verifyAsync']>
) {
return this.service(tokenType).verifyAsync(...rest);
}
decode(tokenType: JwtTokenType, ...rest: Parameters<JwtService['decode']>) {
return this.service(tokenType).decode(...rest);
}
private service(tokenType: JwtTokenType): JwtService {
switch (tokenType) {
case 'access':
return this.jwtAccessService;
case 'refresh':
return this.jwtRefreshService;
}
}
}
- Provide the custom implementations in your module configuration:
import { Module } from '@nestjs/common';
import { JwtModule } from '@concepta/nestjs-jwt';
import { CustomJwtIssueService } from './custom-jwt-issue.service';
import { CustomJwtVerifyService } from './custom-jwt-verify.service';
@Module({
imports: [
JwtModule.forRoot({
jwtIssueService: CustomJwtIssueService,
jwtVerifyService: CustomJwtVerifyService,
settings: {
access: {
secret: 'your-secret-key',
signOptions: { expiresIn: '60s' },
},
},
}),
],
providers: [CustomJwtIssueService, CustomJwtVerifyService],
})
export class AppModule {}
This example shows how to customize the JwtIssueService
and JwtVerifyService
with custom implementations. Similar steps can be followed to override other
services in JwtModule
.
Explanation
Conceptual Overview
What is This Library?
The nestjs-jwt
library is a comprehensive solution for managing authentication
processes within a NestJS application. It provides services for issuing JWTs,
validating user credentials, and verifying tokens. The library integrates
seamlessly with other modules in the nestjs-auth
suite, making it a versatile
choice for various authentication needs.
Benefits of Using This Library
- Secure Token Management: Robust mechanisms for issuing and managing access and refresh tokens.
- Abstract User Validation Service: Flexible user validation service that can be customized to meet specific requirements.
- Token Verification: Capabilities to verify the authenticity and validity of tokens, with support for additional custom validations.
- Customizable and Extensible: Designed to be flexible, allowing customization of token generation, user validation, and token verification processes.
- Integration with NestJS Ecosystem: Seamlessly integrates with other NestJS modules and services, leveraging the framework's features for enhanced functionality and performance.
Design Choices
Global, Synchronous vs Asynchronous Registration
The nestjs-jwt
module supports both synchronous and asynchronous registration:
- Global Registration: Makes the module available throughout the entire application. This approach is useful when JWT authentication is required across all or most routes in the application.
- Synchronous Registration: This method is used when the configuration options are static and available at application startup. It simplifies the setup process and is suitable for most use cases where configuration values do not depend on external services.
- Asynchronous Registration: This method is beneficial when configuration options need to be retrieved from external sources, such as a database or an external API, at runtime. It allows for more flexible and dynamic configuration but requires an asynchronous factory function.
Integration Details
Integrating with Other Modules
The nestjs-jwt
module integrates smoothly with other modules in the
nestjs-auth
suite. Here are some integration details:
- @concepta/nestjs-auth-jwt: Use
@concepta/nestjs-auth-jwt
for JWT-based authentication. Configure it to handle the issuance and verification of JWT tokens. - @concepta/nestjs-auth-local: Use
@concepta/nestjs-auth-local
for local authentication strategies such as username and password. - @concepta/nestjs-auth-recovery: Use
@concepta/nestjs-auth-recovery
for account recovery processes like password reset. - @concepta/nestjs-auth-refresh: Use
@concepta/nestjs-auth-refresh
for handling token refresh mechanisms.
By combining these modules, you can create a comprehensive authentication system that meets various security requirements and user needs.
References
For further details and external references, please visit the following link:
External Authentication References
This link provides additional information and resources related to the authentication processes and best practices in NestJS applications.