JWT authentication with NestJS
A Backend JWT Application
Summary
- What is NestJS?
- What is JWT?
- Starting the NestJS Backend
- NestJS Modules & Components
- Bcrypt Password
- REST Client for VSCode
- JWT Token
- Passport NodeJS Authentication
- References
1. What is NestJS?
- NestJS is a Node Framework 🆓
- Since 2017 🆕
- CoC — Convention Over Configuration 🧾
- TypeScript´👨💻
- Scalable Architecture 🧗♀️
- Integration with multiple databases 💿
- MicroService Support 🚀
- API REST 📲
Value offer
The NestJS Value Proposition is to use an MVC architecture in an agile way
NestJS Language
Uses TypeScript as a development language, Jest with Test Tools, and AngularJS concepts
NestJS with Postgres Database
The NestJS Value Proposition is to use an MVC architecture in an agile way
2. What is JWT?
- JSON Web Token
- API REST-based on HTTP Stateless requisition
- Uses a Token and not a Cookie
Use Cases with Cookie Auth
- Only Web Browser Application
Use Cases with Token Auth
- Mobile
- Desktop
- CLI
- IoT
3. Starting the NestJS Backend
node --versionnpm install -g @nestjs/clinest new authentication-with-NestJS
¨npm run start:dev
4. Concepts of NestJS?
a) NestJS Modules & Components
- Module A to Feature 1
- Module B to Feature 2
b) Clean Architecture
- Use Case ===> Feature
- Repository Interfaces
- Domain Services
- Domain Model
c) Generate an NestJS Module
nest g module auth// Output/src/auth/auth.module.ts
c) Generate an NestJS Controller
/ // root
/auth // auth module
/auth/login // controler loginnest g controller auth/login
- login.controller.spec.ts
import { Test, TestingModule } from '@nestjs/testing';import { LoginController } from './login.controller';describe('LoginController', () => {let controller: LoginController;beforeEach(async () => {const module: TestingModule = await Test.createTestingModule({controllers: [LoginController],}).compile();controller = module.get<LoginController>(LoginController);});it('should be defined', () => {expect(controller).toBeDefined();});});
- login.controller.ts
import { Controller } from '@nestjs/common';@Controller('login')export class LoginController {}/ // root
/auth // auth module
/auth/login // controler login
/auth/auth // controler auth// Generate Auth Controller
nest g controller auth/auth
// Generate Auth Service to Access Database
nest g service auth/auth
5. BCrypt Password
bcrypt is a password-hashing function designed by Niels Provos and David Mazières, based on the Blowfish cipher and presented at USENIX in 1999.[1] Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.
The bcrypt function is the default password hash algorithm for OpenBSD[2] and was the default for some Linux distributions such as SUSE Linux.[3]
npm install bcrypt --save
generate-pass.js
const bcrypt = require('bcrypt');const saltRounds = 10;const password = process.argv.slice(2)[0];bcrypt.genSalt( saltRounds,function(err, salt){bcrypt.hash(password, salt, function(err,hash){console.log(hash)})});
Password Generate
node generate-pass.js 12345678910
❯ node generate-pass.js 12345678910
$2b$10$OLBu.sG9stD6j3PpeO6sw.QuZmxk4RUnfMVTJ.8afMLdj/9HwsRGC
❯
6. REST Client for VS CODE
REST ClientGET https://example.com/comments/1 HTTP/1.1
###
GET https://example.com/topics/1 HTTP/1.1
###
POST https://example.com/comments HTTP/1.1
content-type: application/json
{
"name": "sample",
"time": "Wed, 21 Oct 2015 18:27:50 GMT"
}
POST Method
GET Method
7. JWT Token
- JWT — JSON Web Token
- Header
- Payload
- Signature
- AutoContent
JWT = (1) Header + (2) Payload + (3) Signature
1) Header
2) Payload
- jwt.ts
const header: {alg: string, typ: string; } = {alg: 'HS256',typ: 'JWT',};const payload: {username: string; name:string; exp:number;} = {username: 'user1@user.com',name: 'Luiz Carlos',exp: new Date().getTime(), //timestamp};const key: "abcd123456" = 'abcd123456';// header + payload + key// base64const headerEncoded = Buffer.from( JSON.stringify(header)).toString("base64");const payloadEncoded = Buffer.from( JSON.stringify(payload)).toString("base64");console.log("1.0) Header -----------------------------------");console.log("1.1) header > ", header);console.log("1.2) headerEncoded > ", headerEncoded);console.log("2.0) Payload -----------------------------------");console.log("2.1) payload > ", payload);console.log("2.2) payloadEncoded > ", payloadEncoded);node_modules/.bin/ts-node jwt.ts
3) Signature
const key: "abcd123456" = 'abcd123456';const crypt = require('crypto');const signature = crypt.createHmac('sha256',key).update(`${headerEncoded}.${payloadEncoded}`).digest("bin");console.log("3.0) Signature -----------------------------------");console.log("3.1) signature > ", signature);
Install Library base64-URL
npm install base64-url --save
Implementation base64Url(signature)
const base64Url = require('base64url');console.log("Token JWT - JSON Web Token Created");console.log("JWT = [Header] + [Payload] + [Signature]");console.log("JWT [Token] >",`${headerEncoded}.${payloadEncoded}.${base64Url(signature)}`);
Token JWT = [header] + [Payload] + [Signature]
Token JWT
JWT [Token] > eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxQHVzZXIuY29tIiwibmFtZSI6Ikx1aXogQ2FybG9zIiwiZXhwIjoxNjQxNzk4ODA5MjM2fQ==.WS6MhFktJki4cZSZu56mu1rFVUG7ANJfZfJhTfXpWwo
Validation Token JWT
JWT with Bug 🏸
JWT Correct !!!🚀
- Token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxQHVzZXIuY29tIiwibmFtZSI6Ikx1aXogQ2FybG9zIiwiZXhwIjoxNjQxNzk5NTkzMDc4fQ==.m9DFawDnG07PErE1PN8v0YMDN2xBFX2b6Xv8qOf_7mw
- Secret
const key: "abcd123456" = 'abcd123456';
Othe Example
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxQHVzZXIuY29tIiwibmFtZSI6Ikx1aXogQ2FybG9zIiwiZXhwIjoxNjQxODAxMDg3NTkxfQ.wF9iAYt9vqhHHgutq8bEWPO7HPDwAAP5Np3gj_VfjG8
8. Passport NodeJS Authentication
Simple, unobtrusive authentication for Node.js
app.js — vim
passport.authenticate(‘facebook’);(‘google’);(‘apple’);(‘microsoft’);(‘twitter’);(‘linkedin’);(‘github’);(‘openid’);
Passport is authentication middleware for Node.js. Extremely flexible and modular, Passport can be unobtrusively dropped in to any Express-based web application. A comprehensive set of strategies support authentication using a username and password, Facebook, Twitter, and more.
npm install passport --savenpm install passport-jwt --savenpm install @types/passport --save-devnpm install @types/passport-jwt --save-devnpm install @nestjs/jwt
NestJS Generate Auth Strategy
nest g service auth/jwt-strategynpm install @nestjs/passport --save
Test Application
npm run start:dev
Test API
/api/post.api.htpp
Our JWT Token
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEsInVzZXJuYW1lIjoidXNlcjFAdXNlci5jb20iLCJpYXQiOjE2NDE4NDQyNDUsImV4cCI6MTY0MTg0NDMwNX0.1mH-PD-s8712sILMCMBQX0_KlDX0df3jNneo_bIhb00"
Access control with Token Authenticated
- Guardian Tokens Access Authenticated
@UseGuards(JwtGuard)
- authController.ts
import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';import { AuthService } from './auth.service';import { JwtGuard } from './jwt.guard';@Controller()export class AuthController {constructor(private authService: AuthService){}@Post('login')login(@Body() body ): {token:string} {return { token: this.authService.login(body.username, body.password)}}// Criação Guardiao@UseGuards(JwtGuard) // <<<<< Guardian Token@Get('autenticado')test(){return {name: "Pedro Alvares Cabral"}}}