API Reference
Rockets Core API
nestjs-auth-refresh
README

Rockets NestJS Refresh Authentication

Authenticate requests using JWT refresh tokens passed via the request (headers, cookies, body, query, etc).

Project

NPM Latest (opens in a new tab) NPM Downloads (opens in a new tab) GH Last Commit (opens in a new tab) GH Contrib (opens in a new tab) NestJS Dep (opens in a new tab)

Table of Contents

Tutorials

1. Getting Started with AuthRefreshModule

1.1 Introduction

Overview of the Library

The AuthRefreshModule is a powerful yet easy-to-use NestJS module designed for implementing JWT refresh token functionality. With a few simple steps, you can integrate secure token refreshing into your application without hassle.

Purpose and Key Features
  • Ease of Use: The primary goal of AuthRefreshModule is to simplify the process of adding JWT refresh token functionality to your NestJS application. All you need to do is provide configuration data, and the module handles the rest.
  • Synchronous and Asynchronous Registration: Flexibly register the module either synchronously or asynchronously, depending on your application's needs.
  • Global and Feature-Specific Registration: Register the module globally or for specific features within your application, allowing for more granular control over authentication and authorization requirements.

1.2 Installation

Install the AuthRefreshModule package

To install the AuthRefreshModule package, run the following command in your terminal:

npm install @concepta/nestjs-auth-refresh
Add the AuthRefreshModule to Your NestJS Application

To add the AuthRefreshModule to your NestJS application, import the module in your main application module (usually app.module.ts) and register it using the forRoot or forRootAsync method:

import { AuthRefreshModule } from '@concepta/nestjs-auth-refresh';
 
@Module({
  imports: [
    AuthRefreshModule.forRoot({
      // Configuration options
    }),
  ],
})
export class AppModule {}

1.3 Basic Setup in a NestJS Project

Scenario: Refreshing JWT Tokens

To demonstrate the basic setup of the AuthRefreshModule, let's consider a scenario where we want to refresh JWT tokens. In this example, we will use @concepta/nestjs-auth-refresh in conjunction with other essential modules such as @concepta/nestjs-auth-jwt, @concepta/nestjs-auth-local, and @concepta/nestjs-authentication. These modules work together to provide a comprehensive and secure token refresh mechanism.

For more detailed instructions on setting up the authentication modules, please refer to the Authentication Module Documentation (opens in a new tab). We will continue with the tutorial in the Authentication Module Documentation (opens in a new tab).

Adding AuthRefreshModule to your NestJS Application

To add the AuthRefreshModule to your NestJS application, import the module in your main application module (usually app.module.ts) and register it using the forRoot or forRootAsync method, let's use the MyJwtUserLookupService created at Authentication Module Documentation (opens in a new tab):

//...
AuthRefreshModule.forRoot({
  userLookupService: new MyJwtUserLookupService()
}),
//... 

Additionally, you can take advantage of the MyUserLookupService from the @concepta/nestjs-user module to streamline user lookup operations within your authentication flow, check User Module Documentation for reference:

By default, AuthRefreshModule uses services defined in the AuthenticationModule to verify refresh tokens. However, you can override this behavior by providing a custom service specifically for the refresh token implementation during the module setup.

1.4 First Token Refresh

Validating the Setup

To validate the setup, let's test the refresh token functionality using CURL commands.

Step 1: Obtain a Refresh Token

First, obtain a refresh token by sending a request to the /auth/login endpoint with valid credentials:

curl -X POST \
  http://localhost:3000/auth/login\
  -H 'Content-Type: application/json' \
  -d '{"username":"user@example.com","password":"password"}'

This should return a response with an access token and a refresh token.

Step 2: Refresh the JWT Token

Next, use the obtained refresh token to refresh the JWT token:

curl -X POST \
  http://localhost:3000/auth/refresh \
  -H 'Content-Type: application/json' \
  -d '{"refreshToken":"[refresh_token_value]"}'

This should return a new access token and a new refresh token.

Example CURL Calls
Obtain a Refresh Token
curl -X POST \
  http://localhost:3000/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"user@example.com","password":"password"}'
Example Refresh Token Response
{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cC...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cC..."
}
Refresh the JWT Token
curl -X POST \
  http://localhost:3000/auth/refresh \
  -H 'Content-Type: application/json' \
  -d '{"refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cC..."}'
Response (example)
{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cC...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cC..."
}

How-To Guides

1. Registering AuthRefreshModule Synchronously

//...
AuthRefreshModule.register({
  userLookupService: new MyUserLookupService(),
  issueTokenService: new MyIssueTokenService(),
}),
//...

2. Registering AuthRefreshModule Asynchronously

//...
AuthRefreshModule.registerAsync({
  inject: [MyUserLookupService, MyIssueTokenService],
  useFactory: async (
    userLookupService: MyUserLookupService,
    issueTokenService: MyIssueTokenService
  ) => ({
    userLookupService,
    issueTokenService,
  }),
}),
//...

3. Global Registering AuthRefreshModule Asynchronously

//...
AuthRefreshModule.forRootAsync({
  inject: [MyUserLookupService, MyIssueTokenService],
  useFactory: async (
    userLookupService: MyUserLookupService,
    issueTokenService: MyIssueTokenService
  ) => ({
    userLookupService,
    issueTokenService,
  }),
}),
//...

4. Using Custom User Lookup Service

//...
@Injectable()
export class MyUserLookupService extends AuthRefreshUserLookupServiceInterface {
  constructor(private userService: UserService) {}
 
  async bySubject(subject: ReferenceSubject): Promise<ReferenceIdInterface> {
    // return authorized user
    return this.userService.findOne(subject);
  }
}
//...

5. Implementing and Using Custom Token Verification Service

By default, AuthRefreshModule uses services defined in the AuthenticationModule to verify refresh tokens. However, you can override this behavior by providing a custom service specifically for the refresh token implementation during the module setup.

For more details on implementing a custom token verification service, refer to section 5 of the How-To Guide in the @concepta/nestjs-auth-jwt documentation.

6. Overwriting the Settings

  // app.module.ts
import { Module } from '@nestjs/common';
import { ExtractJwt } from '@concepta/nestjs-jwt';
import { AuthRefreshModule, AuthRefreshSettingsInterface } from '@concepta/nestjs-auth-refresh';
 
const settings: AuthRefreshSettingsInterface = {
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  verifyToken: async (token: string, done: (error: any, payload?: any) => void) => {
    try {
      const payload = { id: 'user-id' };
      done(null, payload);
    } catch (error) {
      done(error);
    }
  },
};
 
@Module({
  imports: [
    AuthRefreshModule.registerAsync({
      useFactory: async () => ({
        settings,
      }),
    }),
  ],
})
export class AppModule {}

7. Integration with Other NestJS Modules

Integrate @concepta/nestjs-auth-refresh with other NestJS modules like @concepta/nestjs-user, @concepta/nestjs-auth-local, @concepta/nestjs-auth-jwt, and more for a comprehensive authentication system.

Engineering Concepts

Conceptual Overview of JWT Refresh Tokens

What is a Refresh Token?

A refresh token is a special token used to obtain a new access token without requiring the user to re-authenticate. It is typically issued alongside the access token and has a longer expiration time.

Benefits of Using Refresh Tokens

  • Improved Security: By using refresh tokens, access tokens can have shorter lifespans, reducing the risk of token theft.
  • Enhanced User Experience: Users do not need to log in frequently, as refresh tokens can be used to obtain new access tokens seamlessly.
  • Scalability: Refresh tokens allow for stateless authentication, which is ideal for scalable applications.

Design Choices in AuthRefreshModule

Why Use NestJS Guards?

NestJS guards provide a way to control access to various parts of the application by checking certain conditions before the route handler is executed. In AuthRefreshModule, guards are used to implement authentication and authorization logic. By using guards, developers can apply security policies across routes efficiently, ensuring that only authenticated and authorized users can access protected resources.

Synchronous vs Asynchronous Registration

The AuthRefreshModule supports both synchronous and asynchronous registration:

  • 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.

Global vs Feature-Specific Registration

The AuthRefreshModule can be registered globally or for specific features:

  • Global Registration: Makes the module available throughout the entire application. This approach is useful when JWT refresh functionality is required across all or most routes in the application.

  • Feature-Specific Registration: Allows the module to be registered only for specific features or modules within the application. This provides more granular control, enabling different parts of the application to have distinct authentication and authorization requirements.

Integrating AuthRefreshModule with Other Modules

How AuthRefreshModule Works with AuthJwtModule

The AuthRefreshModule can be seamlessly integrated with the AuthJwtModule to provide a comprehensive authentication solution. AuthJwtModule handles the initial authentication using JWT tokens.

Once the user is authenticated, AuthRefreshModule can issue a refresh token that the user can use to obtain new access tokens. This integration allows for secure and efficient authentication processes combining the strengths of both modules.

Integrating with AuthLocalModule

Integrating AuthRefreshModule with AuthLocalModule enables the application to handle token refresh logic alongside local authentication. This setup enhances the user experience by maintaining sessions securely and seamlessly. The integration involves configuring both modules to use the same token issuance and verification mechanisms, ensuring smooth interoperability and security.