@webundsoehne/register
TypeScript icon, indicating that this package has built-in type declarations

3.0.1 • Public • Published

Web und Söhne - Logo

Web & Söhne is Austria's leading expert in programming and implementing complex and large web projects.

Introduction

  • The aim of this project is to provide an easy-to-use user authentication flow
  • The process should be standardized as much as possible, but at the same time provide many possibilities for customization
  • The provided module automatically provides several endpoints (each can be configured individually) for register, login, token refreshing, email confirmation and password reset (+ swagger documentation)

Requirements

  • NestJS v8.0.0+
  • [Optional] for Email queueing: One or many redis instance(s)
  • Any (SQL) Database that is supported by TypeOrm (https://typeorm.io/#/)

Brief overview of endpoints

  • After initializing the provided AuthModule (step-by-step description see below) the following endpoints will be attached automatically
Path Usage Method
/auth/register Register new users POST
/auth/login Login user (generate jwtToken and optionally refreshToken POST
/auth/email/validate/:token Validate email token GET
/auth/confirmation/resend/:id Resend email confirmation mail POST
/auth/password/reset/init Initialize password reset POST
/auth/password/reset/check/:token Check if provided password reset token is valid GET
/auth/password/reset/:token Check if token is valid and reset password POST
/auth/password/validate Check if a password meets all requirements POST

Step by Step Guide

  • Initialize TypeOrm.forRoot() in your main module (not part of this module, but this packages needs a database connection)
  • Create your own Entity and extend UserEntity provided by this package (and name all your additional properties etc.)
  • Create your own DTO and extend RegisterDto provided by this package (name your additional properties and make sure they match at least the required fields in your extended custom UserEntity) The provided UserEntity automatically creates the following database schema for you
Name Type Usage
id int Unique user identifier
email varchar(255) User's Email
password varchar(255) User's (hashed) password
isBanned tinyint(1) Whether user is banned or not
lastLogin timestamp Latest user's login
emailVerifyToken varchar(255) User's (hashed) email verify token
emailVerifyTokenValidUntil timestamp User's verify token expire date
refreshToken varchar(255) User's (hashed) refresh token
refreshTokenValidUntil timestamp User's refresh token expire date
passwordResetToken varchar(255) User's password reset token
passwordResetTokenValidUntil timestamp User's password reset token expire date
passwordLastChanged timestamp Time the user last changed their password
previousPasswords text User's previous (hashed) passwords, if enabled in config via denyPreviousPasswords
failedLoginAttempts int Number of user's failed login attempts, reset to 0 after every successful login
lastFailedLoginAttempt timestamp Time of user's last failed login attempt

I would advise that you create your own entity even if you do not need additional fields

Sample code:

import { Entity } from 'typeorm'
import { UserEntity } from '@webundsoehne/register'

@Entity()
export class Customer extends UserEntity {
   @Column({ nullable: false })
   name: string

   @Column()
   city?: string | null
}

Sample code:

import { IsString, MaxLength } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { RegisterDto } from '@webundsoehne/register';


export class RegisterCustomerDto extends RegisterDto {
 @ApiProperty({ type: String })
 @IsString()
 @MaxLength(255)
 @IsDefined()
 name: string;
}
  • Initialize provided AuthModule in your (main) module and configure it!
  • There are lots of different options to customize the experience! Do not worry as it seems overwhelming at first, but it actually is quite straight forward!
  • The sample code provides a minimal configuration object which should be enough!
import { AuthModule } from '@webundsoehne/register'
import { Customer } from './customer.entity'

@Module({
    controllers: [],
    imports: [
        AuthModule.init({ queue: { useRedisQueue: false }, tokenOptions: { salt: 'secret' }, userEntity: Customer, registerDto: RegisterCustomerDto, email: { nodemailerOptions: { smtp: 'hallo.smtp.at', port: 1234, secure: false }, emailValidationRequired: true }})
    ],
    providers: []
})
export class MainModule {}

Configuration object parameters (InitData)

  • You can provide many different configuration options - I will explain them key by key, because I think that this is easier to grasp this way (instead of one huge table)

userEntity (REQUIRED)

  • Provide your custom UserEntity (see above) here!

registerDto (NEW in v1.0.2)

  • Provide your custom registerDto (see above) here!
  • make sure to extend class RegisterDto
  • You can also manipulate these fields with interceptors if you need more complexity for your register endpoints

queue (RECOMMENDED)

  • It is strongly advised to use NestJS Bull Queue (https://docs.nestjs.com/techniques/queues) for sending emails since email will be sent in a non-blocking manner - REQUIRES: one (or many) redis instance(s)!
  • useRedisQueue (boolean): Whether or not to use NestJS Bull Queue (default: true)
  • bullQueueOptions (BullModuleOptions): used to register NestJS Bull Queue (options see: (https://docs.nestjs.com/techniques/queues))
  • bullJobOptions (JobOptions): these options will passed to each (email) job appended to queue

passwordResetSettings (OPTIONAL)

  • Set TTL for password reset token (that's the time that will be appended to the token's creation date - after that duration the token is no longer valid and you have to request a new token)
  • tokenDuration (number): Token TTL duration (default: 14)
  • tokenUnit (DurationEnum): Token TTL unit (default: days)

emailTemplatesService (OPTIONAL)

  • default: EmailTemplatesService
  • See below for a detailed explanation about custom emailTemplateService

email (REQUIRED)

  • emailValidationRequired (boolean): Whether or not the user has to validate their email address (click link in email address)
  • tokenDuration (number): Token TTL duration (default: 14)
  • tokenUnit (DurationEnum): Token TTL unit (default: days)
  • nodemailerOptions (EmailConfigOptions): will be used to construct a nodemailer transport (https://nodemailer.com/about/)
  • templateSettings (TemplateSettings): see below

templateSettings

  • This settings will be used to generate email Template which will be sent on different occasions
  • baseUri: baseUri for your frontend application
  • applicationName: Name of your application
  • validateEmail: (custom options) for email validation email
  • validateEmail.subject: Subject of email validation mail
  • validateEmail.frontendPath: path for your frontend (baseUri + frontendPath)
  • validateEmail.from: from which email should it be sent from?
  • resetPasswordPath: (custom options) for reset password email
  • resetPasswordPath.subject: Subject of reset path mail
  • resetPasswordPath.frontendPath: path for your frontend (baseUri + frontendPath)
  • resetPasswordPath.from: from which email should it be sent from?

tokenOptions (REQUIRED)

  • hashAlgorithm: which hash algorithm should be used to hash the generate (uuid) tokens (default: sha256)
  • salt: additional salt which is appended to each (uuid) token before hashing (improves security) (default: thisisaverysecretsalt - but please make sure to overwrite this property!!)

refreshTokenOptions (OPTIONAL)

  • tokenDuration (number): Token TTL duration (14)
  • tokenUnit (DurationEnum): Token TTL unit (days)

passwordOptions (OPTIONAL)

  • You can provide either minLength (then only minLength will be checked) or custom regular expression (REGEX) ==> overwrites minLength!
  • minLength (number): Minimum length for password (is overwritten if you provide regex) (default: 7)
  • errorMessage (string): Custom error message if password does not meet requirements (default: "Password does not satisfy requirements!")
  • regex (string): Will be passed to Javascript RegExp constructor if set
  • validityDuration (number): Determines after what time users are forced to update their passwords. (-1 = never) (default: -1)
  • validityDurationUnit (DurationEnum): validityDuration unit (default: days)
  • denyPreviousPasswords (number): Number of previous passwords that should be saved for each user. Users will be denied from changing their password to one of the old ones (default: 0)
  • blacklist:

securityOptions (OPTIONAL)

  • accountLockoutThreshold (number): Number of times a user can enter wrong credentials before the account gets locked. Durations can be provided via accountLockoutDurations. (-1 = infinite times) (default: -1)
  • accountLockoutDurations (number[]): Number of minutes an account should get locked after exceeding the lockoutThreshold. On every continuously failed login attempt, the index will be increased by one. E.g.: [1, 5, -1] will lock out accounts for 1 minute initially, 5 minutes after another failed login attempt, and forever (-1 = forever) after a third failed login attempt. If the number of continuously failed login attempts exceeds the length of this array, the last duration will be used. Index will be reset on successful login. (default: [-1])

jwtPayloadFields (OPTIONAL)

  • string | string[]
  • Specify all the database fields which should be your jwt token's payload!
  • if you just pass a string instead of a string array all the fields will be appended to JWT payload
  • Basically the fields you specify here will later be accessible by JwtUser decorator in your routes!
  • Default: [id, email]

jwtOptions (REQUIRED)

  • JwtModuleOptions
  • jwtOptions.secret -> secret used for jwtToken please make sure to overwrite this! (default: 'thisisaverysecretstring')
  • jwtOptions.signOptions.expiresIn -> how long is jwtToken valid? (default: 1h)
  • There are many more options which you can find either via interface or https://github.com/auth0/node-jsonwebtoken#usage

jwtStrategyOptions

jwtSignOptions

  • Used to sign jwt tokens

routes

  • This option can be used to configure the different routes

  • Detailed explanation of each endpoint see above: they all come with a prefix of /auth

  • registerUser (/register)

  • loginUser (/login)

  • refreshToken (/refresh)

  • validateEmail (/email/validate/:token)

  • resendConfirmation (/confirmation/resend/:id)

  • initPasswordReset (/password/reset/init)

  • checkPasswordResetToken (/password/reset/check/:token)

  • checkPasswordResetTokenAndSetPassword (/password/reset/:token)

  • validatePassword (/password/validate)

RouteConfig object

  • each route can be configured with these options
  • endpointPath (string): change path of endpoint (if you ever want to change the endpoint path and there are placeholders (for token, id etc.) make sure to include them as well or otherwise the endpoint will not function correctly anymore!)
  • method (RequestMethod): request method (I would not recommend to ever change it)
  • interceptors (NestJS Interceptor): NestJS Interceptors that should be registered for this endpoint
  • enable (boolean): whether or not the endpoint should be enabled

EmailTemplateService

  • There are 2 emails which will be sent out to the user automatically
  • These emails are not really fancy but they function well
  • You probably want to create your own templates (with your company's logo custom text etc.). This can be done by providing your own emailTemplateService to init method of AuthModule
  • Optionally your interface can inject the whole config object (that you provide while initializing AuthModule) (see example below)
  • Just create a Service that extends EmailTemplatesService and (optionally) implements provided interface EmailTemplatesInterface and just import it as provider in your main module!
  • Each method is called with data of interface TokenData and expects a Promise which resolves to data of type Email interface

TokenData interface

  • token: uuid token used to identify user
  • email: user's email
  • tokenValidUntil: timestamp until the token is valid

Email interface

  • from (string) (REQUIRED): Sender's email address
  • to (string) (REQUIRED): Recipient's email address
  • subject (string) (REQUIRED): Email's subject
  • text (string) (REQUIRED): Email's text
  • bcc (string) (OPTIONAL): Email's bcc
  • cc (string) (OPTIONAL): Email's cc
  • html (string) (OPTIONAL): Email's HTML text
  • attachments (EmailAttachment[]) (OPTIONAL): Optional email attachments (base64 format)

Welcome email

  • Sent after user registration
  • include token which can be used to validate user's email

Password reset email

  • Sent after user requests password reset
  • include token which can be used to validate user's email

Example for custom emailTemplateService

  • Make sure to import this as a provider in your main module and set emailTemplateService option (for AuthModule.init(...))!)
import { Inject, Injectable, Optional } from '@nestjs/common'
import { InitData, Email, TokenData, EmailTemplatesInterface, EmailTemplatesService } from '@webundsoehne/register'

@Injectable()
export class CustomEmailTemplatesService extends EmailTemplatesService implements EmailTemplatesInterface {
    constructor (@Optional() @Inject(CONFIG_TOKEN) private config: InitData) {}

    async getWelcomeMailTemplate (data: TokenData): Promise<Email> { ... }

    async getPasswordResetInitMailTemplate (data: TokenData): Promise<Email> { ... }
}

Stay in touch

Package Sidebar

Install

npm i @webundsoehne/register

Weekly Downloads

4

Version

3.0.1

License

ISC

Unpacked Size

377 kB

Total Files

117

Last publish

Collaborators

  • ws-admin
  • dabls