nestjs-boilerplate

Auth

Table of Contents


General info

Auth via email flow

By default boilerplate used sign in and sign up via email and password.

sequenceDiagram
    participant A as Fronted App (Web, Mobile, Desktop)
    participant B as Backend App

    A->>B: 1. Sign up via email and password
    A->>B: 2. Sign in via email and password
    B->>A: 3. Get a JWT token
    A->>B: 4. Make any requests using a JWT token

https://user-images.githubusercontent.com/6001723/224566194-1c1f4e98-5691-4703-b30e-92f99ec5d929.mp4

Auth via external services or social networks flow

Also you can sign up via another external services or social networks like Apple, Facebook, Google, and Twitter.

sequenceDiagram
    participant B as External Auth Services (Apple, Google, etc)
    participant A as Fronted App (Web, Mobile, Desktop)
    participant C as Backend App

    A->>B: 1. Sign in through an external service
    B->>A: 2. Get Access Token
    A->>C: 3. Send Access Token to auth endpoint
    C->>A: 4. Get a JWT token
    A->>C: 5. Make any requests using a JWT token

For auth with external services or social networks you need:

  1. Sign in through an external service and get access token(s).
  2. Call one of endpoints with access token received in frontend app on 1-st step and get JWT token from the backend app.

    POST /api/v1/auth/facebook/login
    
    POST /api/v1/auth/google/login
    
    POST /api/v1/auth/twitter/login
    
    POST /api/v1/auth/apple/login
    
  3. Make any requests using a JWT token

Configure Auth

  1. Generate secret keys for access token and refresh token:

    node -e "console.log('\nAUTH_JWT_SECRET=' + require('crypto').randomBytes(256).toString('base64') + '\n\nAUTH_REFRESH_SECRET=' + require('crypto').randomBytes(256).toString('base64') + '\n\nAUTH_FORGOT_SECRET=' + require('crypto').randomBytes(256).toString('base64') + '\n\nAUTH_CONFIRM_EMAIL_SECRET=' + require('crypto').randomBytes(256).toString('base64'));"
    
  2. Go to /.env and replace AUTH_JWT_SECRET and AUTH_REFRESH_SECRET with output from step 1.

    AUTH_JWT_SECRET=HERE_SECRET_KEY_FROM_STEP_1
    AUTH_REFRESH_SECRET=HERE_SECRET_KEY_FROM_STEP_1
    

Auth via Apple

  1. Set up your service on Apple
  2. Change APPLE_APP_AUDIENCE in .env

    APPLE_APP_AUDIENCE=["com.company", "com.company.web"]
    

Auth via Facebook

  1. Go to https://developers.facebook.com/apps/creation/ and create a new app image

    image

  2. Go to Settings -> Basic and get App ID and App Secret from your app image
  3. Change FACEBOOK_APP_ID and FACEBOOK_APP_SECRET in .env

    FACEBOOK_APP_ID=123
    FACEBOOK_APP_SECRET=abc
    

Auth via Google

  1. You need a CLIENT_ID, CLIENT_SECRET. You can find these pieces of information by going to the Developer Console, clicking your project (if doesn’t have create it here https://console.cloud.google.com/projectcreate) -> APIs & services -> credentials.
  2. Change GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in .env

    GOOGLE_CLIENT_ID=abc
    GOOGLE_CLIENT_SECRET=abc
    

Auth via Twitter

  1. Set up your service on Twitter
  2. Change TWITTER_CONSUMER_KEY and TWITTER_CONSUMER_SECRET in .env

    TWITTER_CONSUMER_KEY=abc
    TWITTER_CONSUMER_SECRET=abc
    

About JWT strategy

In the validate method of the src/auth/strategies/jwt.strategy.ts file, you can see that we do not check if the user exists in the database because it is redundant, it may lose the benefits of the JWT approach and can affect the application performance.

To better understand how JWT works, watch the video explanation https://www.youtube.com/watch?v=Y2H3DXDeS3Q and read this article https://jwt.io/introduction/

// src/auth/strategies/jwt.strategy.ts

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
  // ...

  public validate(payload) {
    if (!payload.id) {
      throw new UnauthorizedException();
    }

    return payload;
  }
}

If you need to get full user information, get it in services.

Refresh token flow

  1. On sign in (POST /api/v1/auth/email/login) you will receive token, tokenExpires and refreshToken in response.
  2. On each regular request you need to send token in Authorization header.
  3. If token is expired (check with tokenExpires property on client app) you need to send refreshToken to POST /api/v1/auth/refresh in Authorization header to refresh token. You will receive new token, tokenExpires and refreshToken in response.

Video example

https://github.com/brocoders/nestjs-boilerplate/assets/6001723/f6fdcc89-5ec6-472b-a6fc-d24178ad1bbb

Logout

  1. Call following endpoint:

    POST /api/v1/auth/logout
    
  2. Remove access token and refresh token from your client app (cookies, localStorage, etc).


Previous: Working with database

Next: Serialization