Git Product home page Git Product logo

nodejs-rest-api-jwt-authentication's Introduction

Nodejs REST API JWT Authentication

A REST API jwt authentication using nodejs and express. This code uses mongoDB as a database. Docker is supported.

We use two collections, one for users and another for tokens. Token refreshing is supported, expired token will be discarded using TTL index of mongoDB.

Access token expiry and refresh token expiry can be tuned in the files controllers/auth.js and models/token.js.

Note that you have to recreate the index of the collection if you updated it.

Key rotation is also implemented, signing keys are changed everyday, this is done by a cron task which can be modified in index.js.

A sample middleware can be found in middlewares/is-auth.js, where 3rd party apps request the public JWKS to verify the tokens.

New users are required to verify their email through a verification link.

Password reset through email is also implemented.

Features

  • Email and Passsword Sign In
  • HCAPTCHA Verification
  • Google Sign In
  • Apple Sign In
  • TOTP authenticator auth
  • Hcaptcha Validation
  • Email verification
  • Email password reset
  • 2 factor authentication (2FA)

Usage

Keypair

Keypair generation is done in utils/keypair.js. If you intend to change the algorithm used, please make sure you update them at signing and verifying respectively.

JWT Audience and issuer

Please change the audience and issuer claim on signing and verifying tokens:

// Signing
const accessToken = await new SignJWT({
  email: user.email,
  userId: user._id.toString(),
  })
  .setProtectedHeader({ alg: 'EdDSA', kid: jwk.kid })
  .setIssuedAt()
  .setIssuer('wmtech')
  .setAudience('auth.wmtech.cc')
  .setExpirationTime(accessTokenExpiry.getTime())
  .sign(privateKey);

// Verifying
const { payload } = await jwtVerify(token, JWKS, {
  issuer: 'wmtech',
  audience: 'auth.wmtech.cc'
});

Hcaptcha

This repo uses hcaptcha validation. Please configure hcaptcha in your frontend respectively. A sample hcaptcha server can be found here.

Nodemailer

Modify the defaultMailOptions in utils/nodemailer.js.

const defaultMailOptions = {
  from: `WMTech <noreply.wmtech.cc>`,
  replyTo: `[email protected]`,
  subject: 'WMTech',
};

Environment Variables

  • SMTP_USER
    • http port to serve the backend
  • SMTP_PASS
    • http port to serve the backend
  • VIRTUAL_HOST
    • url to host this auth service
  • HCAPTCHA_HOST
    • url to hcaptcha backend
  • GOOGLE_CLIENT_ID
    • Google OAuth2 Client ID (For sign in with google)
  • PORT
    • http port to serve the backend
    • default: 80
  • DATABASE_URL
    • mongodb connection url
  • NUM_KEYS
    • number of signing keys to generate
    • default: 5 Instead of hardcoding these values into your docker-compose.yaml, you can create a .env file like below:
DATABASE_URL=<your mongodb connection string>
[email protected]
SMTP_PASS=<password>
VIRTUAL_HOST=https://auth.example.com
HCAPTCHA_HOST=https://hcaptcha.example.com
GOOGLE_CLIENT_ID=<your google client id>

Docker

Dockerfile.dev spawns up a dev server with nodemon for development.

Dockerfile is for deployment.

API Reference

Here are some main api usage, more details can be found in routes.

POST /signup

Request Body

{
    "email": "[email protected]",
    "password": "Te$+12#$",
    "firstName": "Test",
    "lastName": "Test",
    "phoneNumber": "0123456789",
    "token": "HCAPTCHA_TOKEN"
}

/sign_up_with_google and sign_up_with_apple works similarly, justreplace the token field with google auth token/apple auth token. These are called to sign up a user if the user log in with the specific method is not registered.

Respond

{
    "message": "User created!",
    "userId": "5fd21f48601a41001dbd5aef"
}

POST /sign_in_with_email_password

Sign in with email and password

Request Body

{
    "email": "[email protected]",
    "password": "Te$+12#$",
    "token": "HCAPTCHA_TOKEN"
}

Respond

{
    "accessToken": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjA5ZWE4ZmEzNjg0OWVjMjQ1M2Q0YTEyMDg3MDBjMDg2NDlmYzc2MDk1OTRjMTdjMzRmYzE0MTRmYzkxZDgyMjcifQ.eyJlbWFpbCI6InRlc3RAdGVzdC5jb20iLCJ1c2VySWQiOiI1ZmQyMWY0ODYwMWE0MTAwMWRiZDVhZWYiLCJpYXQiOjE2MDc2MDgwMzMsImV4cCI6MTYwNzY5NDQzM30.AAAAAANnSrz4foRuIGGhj46YRajaKO0dHLoKqHJLKLoAAAAAfbmYrk9WMFWmsG9yUPZdQCxug6kGMJEIgHUIfA",
    "refreshToken": "rdhXgbg3qMOvyK1gKwlLu/BA9uHExQ8PlpbSpMGLeJFEXfV8bGCj3n5/R+aXZOEzWovXTu+tirUuJPIycuXc45cQRPYh6LGG+WerPqfHnYaUlpTL6cic5q2vV5Vu491CSRt8X8ku3bIbJ0W2rJe3lvPKYkGEYbPoADdf4O6zac8=",
    "userId": "5fd21f48601a41001dbd5aef",
    "accessTokenExpiry": "2020-12-11T13:47:13.476Z",
    "refreshTokenExpiry": "2020-12-17T13:47:13.476Z",
    "email": "[email protected]",
    "firstName": "Test",
    "lastName": "Test",
    "phoneNumber": "0123456789",
    "activeStatus": false,
    "googleAuthEnabled": false,
    "appleAuthEnabled": false,
    "otpAuthEnabled": false,
    "enable2FA": false
}

POST /sign_in_with_google

Sign in with google

Request Body

{
    "token": "GOOGLE_AUTH_TOKEN"
}

Respond

Similar to sign_in_with_email_password

POST /sign_in_with_apple

Sign in with apple

Request Body

{
    "token": "APPLE_AUTH_TOKEN"
}

Respond

Similar to sign_in_with_email_password

POST /refreshToken

Refresh access token based on refresh token.

Request Body

{
    "accessToken": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjA5ZWE4ZmEzNjg0OWVjMjQ1M2Q0YTEyMDg3MDBjMDg2NDlmYzc2MDk1OTRjMTdjMzRmYzE0MTRmYzkxZDgyMjcifQ.eyJlbWFpbCI6InRlc3RAdGVzdC5jb20iLCJ1c2VySWQiOiI1ZmQyMWY0ODYwMWE0MTAwMWRiZDVhZWYiLCJpYXQiOjE2MDc2MDgwMzMsImV4cCI6MTYwNzY5NDQzM30.AAAAAANnSrz4foRuIGGhj46YRajaKO0dHLoKqHJLKLoAAAAAfbmYrk9WMFWmsG9yUPZdQCxug6kGMJEIgHUIfA",
    "refreshToken": "rdhXgbg3qMOvyK1gKwlLu/BA9uHExQ8PlpbSpMGLeJFEXfV8bGCj3n5/R+aXZOEzWovXTu+tirUuJPIycuXc45cQRPYh6LGG+WerPqfHnYaUlpTL6cic5q2vV5Vu491CSRt8X8ku3bIbJ0W2rJe3lvPKYkGEYbPoADdf4O6zac8="
}

Respond

{
    "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjA5ZWE4ZmEzNjg0OWVjMjQ1M2Q0YTEyMDg3MDBjMDg2NDlmYzc2MDk1OTRjMTdjMzRmYzE0MTRmYzkxZDgyMjcifQ.eyJ1c2VySWQiOiI1ZmQyMWY0ODYwMWE0MTAwMWRiZDVhZWYiLCJpYXQiOjE2MDc2MDg3MDUsImV4cCI6MTYwNzY5NTEwNX0.AAAAAISgA-S1UllqAni924esohWowfEqOei38FEHeegAAAAAdFM0e-sKpoRhYFnHtvYZCGEmE8M2s0_Q2IbG-w",
    "userId": "5fd21f48601a41001dbd5aef",
    "accessTokenExpiry": "2020-12-11T13:58:25.687Z"
}

POST /enable2FA

Enable 2 Factor Authentication. Attach Bearer Token at Authorization header.

Request Body

N/A

Respond

{
  "message": "Success!"
}

POST /disable2FA

Enable 2 Factor Authentication. Attach Bearer Token at Authorization header.

Request Body

N/A

Respond

{
  "message": "Success!"
}

POST /setupOtp

Setup TOTP. Attach Bearer Token at Authorization header.

Request Body

N/A

Respond

{
  "token": "<URL of QR Code to be scanned with Authenticator APP>"
}

POST /disableOtp

Disable TOTP. Attach Bearer Token at Authorization header.

Request Body

N/A

Respond

{
  "message": "Success!"
}

POST /validateOtp

Sign in with TOTP

Request Body

{
    "email": "[email protected]",
    "token": "TOTP"
}

Respond

Similar to sign_in_with_email_password

GET /sendVerificationEmail

Send verification email to user to verify user email. Attach Bearer Token at Authorization header.

Request Body

N/A

Respond

{
  "message": "Success!"
}

GET /verifyEmail/:token

Verify user email based on token attached with email sent. (Used Internally when user clicks on the link on the email.)

POST /sendPasswordResetEmail/:email

Send password reset email to user to reset password.

Request Body

N/A

Respond

{
  "message": "Success!"
}

GET /resetPassword

Get reset password frontend html

GET /resetPassword/:token

Reset user password. (Used Internally when user clicks on the link on the email.)

GET /emailAvailability/:email

Check email availability for new registration.

Request Body

N/A

Respond

{
  "result": true
}

GET /phoneNumberAvailability/:phoneNumber

Check phone number availability for new registration.

Request Body

N/A

Respond

{
  "result": true
}

GET /publicKey

Get public JWKS for token verification.#

nodejs-rest-api-jwt-authentication's People

Contributors

elchin-novruzov avatar

Stargazers

Elvin Novruzov avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.