3.0.1 • Published 3 months ago

@webundsoehne/register v3.0.1

Weekly downloads
229
License
ISC
Repository
-
Last release
3 months ago

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

Brief overview of endpoints

  • After initializing the provided AuthModule (step-by-step description see below) the following endpoints will be attached automatically
PathUsageMethod
/auth/registerRegister new usersPOST
/auth/loginLogin user (generate jwtToken and optionally refreshTokenPOST
/auth/email/validate/:tokenValidate email tokenGET
/auth/confirmation/resend/:idResend email confirmation mailPOST
/auth/password/reset/initInitialize password resetPOST
/auth/password/reset/check/:tokenCheck if provided password reset token is validGET
/auth/password/reset/:tokenCheck if token is valid and reset passwordPOST
/auth/password/validateCheck if a password meets all requirementsPOST
/auth/two-factor-auth/totp/enableEnable TOTP two-factor-authentication for a userPOST
/auth/two-factor-auth/totp/disableDisable TOTP two-factor-authentication for a userPOST
/auth/two-factor-auth/totp/verifyLogin a user with TOTP two-factor-authenticationPOST
/auth/two-factor-auth/email/enableEnable email two-factor-authentication for a userPOST
/auth/two-factor-auth/email/disableDisable email two-factor-authentication for a userPOST
/auth/two-factor-auth/email/verifyLogin a user with email two-factor-authenticationPOST
/auth/two-factor-auth/email/verify/initInitiate email two-factor-authentication (sends the mail)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
NameTypeUsage
idintUnique user identifier
emailvarchar(255)User's Email
passwordvarchar(255)User's (hashed) password
isBannedtinyint(1)Whether user is banned or not
lastLogintimestampLatest user's login
emailVerifyTokenvarchar(255)User's (hashed) email verify token
emailVerifyTokenValidUntiltimestampUser's verify token expire date
refreshTokenvarchar(255)User's (hashed) refresh token
refreshTokenValidUntiltimestampUser's refresh token expire date
passwordResetTokenvarchar(255)User's password reset token
passwordResetTokenValidUntiltimestampUser's password reset token expire date
passwordLastChangedtimestampTime the user last changed their password
previousPasswordstextUser's previous (hashed) passwords, if enabled in config via denyPreviousPasswords
failedLoginAttemptsintNumber of user's failed login attempts, reset to 0 after every successful login
lastFailedLoginAttempttimestampTime 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;
}
  • If you want to use TOTP/Email 2FA: Create your own Entity and extend Totp2faEntity/Email2faEntity provided by this package.
  • 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)
  • enable2faTotp (/two-factor-auth/totp/enable)
  • disable2faTotp (/two-factor-auth/totp/disable)
  • verify2faTotp (/two-factor-auth/totp/verify)
  • enable2faEmail (/two-factor-auth/email/enable)
  • disable2faEmail (/two-factor-auth/email/disable)
  • verify2faEmail (/two-factor-auth/email/verify)
  • initVerify2faEmail (/two-factor-auth/email/verify/init)

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> { ... }
}

TwoFactorAuth (OPTIONAL)

  • enabled (boolean): whether or not two-factor-authentication should be enabled (default: false)
  • encryptionKey (string): A 32 byte encryption key that is used to encrypt sensitive information (e.g, totp secret).

Time-based one-time password (TOTP)

  • providers.totp:
    • enabled (boolean): Whether or not the TOTP provider should be enabled (default: false).
    • numberOfRecoveryCodes (number): The number of recovery codes that should be generated for a user (default: 5).
    • tokenValidFor (number): The interval in seconds that a generated token should be valid for (default: 30).
    • tokenWindow (number): The number of additional consecutive tokens of the past/future that should count as valid (default: 1).
    • qrCodeIssuer (string): A string that will be encoded into the QR Code that is generated when TOTP is enabled for a user. It is usually displayed in authenticator apps.
    • totp2faEntity: The Totp2faEntity that should be used.

Token via E-Mail (EMAIL)

  • providers.email:
    • enabled (boolean): Whether or not the email provider should be enabled (default: false).
    • numberOfRecoveryCodes (number): The number of recovery codes that should be generated for a user (default: 5).
    • tokenValidFor (number): The interval in minutes that a generated token should be valid for (default: 15).
    • numberOfTokenCharacters (number): The number of characters (a-z0-9) that a generated token should have (default: 6).
    • mailTimeout (number): The minimum number of seconds that a user has to wait before initiating another mail (default: 20).
    • email2faEntity: The Email2faEntity that should be used.

Stay in touch

4.0.0-beta.3

3 months ago

5.0.0

3 months ago

4.0.0

4 months ago

3.0.1

2 years ago

4.0.0-beta.2

1 year ago

4.0.0-beta.1

1 year ago

4.0.0-beta.0

1 year ago

3.0.0

2 years ago

2.0.2

2 years ago

2.0.1

2 years ago

2.0.0

2 years ago

1.1.4

3 years ago

1.1.3

3 years ago

1.1.2

3 years ago

1.1.1

3 years ago

1.1.0

3 years ago

1.0.4

3 years ago

1.0.3

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago

0.0.1

4 years ago