├── .gitignore ├── package.json ├── users.json ├── README.md ├── database.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-server-api", 3 | "version": "1.0.0", 4 | "description": "Simple Fake API", 5 | "main": "main.js", 6 | "scripts": { 7 | "start": "json-server --watch ./database.json", 8 | "start-auth": "node server.js" 9 | }, 10 | "author": "ME:)", 11 | "license": "ISC", 12 | "dependencies": { 13 | "body-parser": "^1.19.0", 14 | "json-server": "^0.14.2", 15 | "jsonwebtoken": "^8.1.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /users.json: -------------------------------------------------------------------------------- 1 | {"users":[{"id":1,"email":"bruno@email.com","password":"bruno"},{"id":2,"email":"techie@email.com","password":"techie"},{"id":3,"email":"nilson@email.com","password":"nilson"},{"id":4,"email":"nilson1@email.com","password":"nilson"},{"id":5,"email":"nilson2@email.com","password":"nilson"},{"id":6,"email":"nilson3@email.com","password":"nilson"},{"id":7,"email":"nilson4@email.com","password":"nilson"},{"id":8,"email":"nilson7@email.com","password":"nilson"},{"id":9,"email":"nilson8@email.com","password":"nilson"}]} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSONServer + JWT Auth 2 | 3 | A Fake REST API using json-server with JWT authentication. 4 | 5 | Implemented End-points: login,register 6 | 7 | ## Install 8 | 9 | ```bash 10 | $ npm install 11 | $ npm run start-auth 12 | ``` 13 | 14 | Might need to run 15 | ``` 16 | npm audit fix 17 | ``` 18 | 19 | ## How to login/register? 20 | 21 | You can login/register by sending a POST request to 22 | 23 | ``` 24 | POST http://localhost:8000/auth/login 25 | POST http://localhost:8000/auth/register 26 | ``` 27 | with the following data 28 | 29 | ``` 30 | { 31 | "email": "nilson@email.com", 32 | "password":"nilson" 33 | } 34 | ``` 35 | 36 | You should receive an access token with the following format 37 | 38 | ``` 39 | { 40 | "access_token": "" 41 | } 42 | ``` 43 | 44 | 45 | You should send this authorization with any request to the protected endpoints 46 | 47 | ``` 48 | Authorization: Bearer 49 | ``` 50 | 51 | Check out these tutorials: 52 | 53 | - [Mocking a REST API Back-End for Your Angular App with JSON-Server and Faker.js](https://www.techiediaries.com/angular-mock-backend) 54 | - [Building a Fake and JWT Protected REST API with json-server](https://www.techiediaries.com/fake-api-jwt-json-server) 55 | - [Angular 9 Tutorial: Build an Example App with Angular CLI, Angular Router, HttpClient & Angular Material](https://www.shabang.dev/angular-tutorial-build-an-example-app-with-angular-cli-router-httpclient-and-angular-material/) 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /database.json: -------------------------------------------------------------------------------- 1 | { 2 | "products": [ 3 | { 4 | "id": 1, 5 | "name": "Product001", 6 | "cost": 10, 7 | "quantity": 1000, 8 | "locationId": 1, 9 | "familyId": 1 10 | }, 11 | { 12 | "id": 2, 13 | "name": "Product002", 14 | "cost": 20, 15 | "quantity": 2000, 16 | "locationId": 1, 17 | "familyId": 2 18 | }, 19 | { 20 | "id": 3, 21 | "name": "Product003", 22 | "cost": 30, 23 | "quantity": 3000, 24 | "locationId": 3, 25 | "familyId": 2 26 | }, 27 | { 28 | "id": 4, 29 | "name": "Product004", 30 | "cost": 40, 31 | "quantity": 4000, 32 | "locationId": 2, 33 | "familyId": 3 34 | }, 35 | { 36 | "id": 5 37 | }, 38 | { 39 | "id": 6 40 | }, 41 | { 42 | "id": 7 43 | }, 44 | { 45 | "id": 8 46 | }, 47 | { 48 | "id": 9 49 | }, 50 | { 51 | "id": 10 52 | }, 53 | { 54 | "id": 11 55 | }, 56 | { 57 | "id": 12 58 | }, 59 | { 60 | "id": 13 61 | }, 62 | { 63 | "id": 14 64 | }, 65 | { 66 | "id": 15 67 | }, 68 | { 69 | "id": 16 70 | }, 71 | { 72 | "id": 17 73 | }, 74 | { 75 | "id": 18 76 | } 77 | ], 78 | "locations": [ 79 | { 80 | "id": 1, 81 | "name": "Location001" 82 | }, 83 | { 84 | "id": 2, 85 | "name": "Location002" 86 | }, 87 | { 88 | "id": 3, 89 | "name": "Location003" 90 | } 91 | ], 92 | "families": [ 93 | { 94 | "id": 1, 95 | "name": "FM001" 96 | }, 97 | { 98 | "id": 2, 99 | "name": "FM002" 100 | }, 101 | { 102 | "id": 3, 103 | "name": "FM003" 104 | } 105 | ], 106 | "transactions": [ 107 | { 108 | "id": 1, 109 | "cost": 11, 110 | "quantity": 10, 111 | "productId": 1 112 | }, 113 | { 114 | "id": 2, 115 | "cost": 12, 116 | "quantity": 100, 117 | "productId": 2 118 | }, 119 | { 120 | "id": 3, 121 | "cost": 15, 122 | "quantity": 101, 123 | "productId": 3 124 | } 125 | ] 126 | } -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const bodyParser = require('body-parser') 3 | const jsonServer = require('json-server') 4 | const jwt = require('jsonwebtoken') 5 | 6 | const server = jsonServer.create() 7 | const router = jsonServer.router('./database.json') 8 | const userdb = JSON.parse(fs.readFileSync('./users.json', 'UTF-8')) 9 | 10 | server.use(bodyParser.urlencoded({extended: true})) 11 | server.use(bodyParser.json()) 12 | server.use(jsonServer.defaults()); 13 | 14 | const SECRET_KEY = '123456789' 15 | 16 | const expiresIn = '1h' 17 | 18 | // Create a token from a payload 19 | function createToken(payload){ 20 | return jwt.sign(payload, SECRET_KEY, {expiresIn}) 21 | } 22 | 23 | // Verify the token 24 | function verifyToken(token){ 25 | return jwt.verify(token, SECRET_KEY, (err, decode) => decode !== undefined ? decode : err) 26 | } 27 | 28 | // Check if the user exists in database 29 | function isAuthenticated({email, password}){ 30 | return userdb.users.findIndex(user => user.email === email && user.password === password) !== -1 31 | } 32 | 33 | // Register New User 34 | server.post('/auth/register', (req, res) => { 35 | console.log("register endpoint called; request body:"); 36 | console.log(req.body); 37 | const {email, password} = req.body; 38 | 39 | if(isAuthenticated({email, password}) === true) { 40 | const status = 401; 41 | const message = 'Email and Password already exist'; 42 | res.status(status).json({status, message}); 43 | return 44 | } 45 | 46 | fs.readFile("./users.json", (err, data) => { 47 | if (err) { 48 | const status = 401 49 | const message = err 50 | res.status(status).json({status, message}) 51 | return 52 | }; 53 | 54 | // Get current users data 55 | var data = JSON.parse(data.toString()); 56 | 57 | // Get the id of last user 58 | var last_item_id = data.users[data.users.length-1].id; 59 | 60 | //Add new user 61 | data.users.push({id: last_item_id + 1, email: email, password: password}); //add some data 62 | var writeData = fs.writeFile("./users.json", JSON.stringify(data), (err, result) => { // WRITE 63 | if (err) { 64 | const status = 401 65 | const message = err 66 | res.status(status).json({status, message}) 67 | return 68 | } 69 | }); 70 | }); 71 | 72 | // Create token for new user 73 | const access_token = createToken({email, password}) 74 | console.log("Access Token:" + access_token); 75 | res.status(200).json({access_token}) 76 | }) 77 | 78 | // Login to one of the users from ./users.json 79 | server.post('/auth/login', (req, res) => { 80 | console.log("login endpoint called; request body:"); 81 | console.log(req.body); 82 | const {email, password} = req.body; 83 | if (isAuthenticated({email, password}) === false) { 84 | const status = 401 85 | const message = 'Incorrect email or password' 86 | res.status(status).json({status, message}) 87 | return 88 | } 89 | const access_token = createToken({email, password}) 90 | console.log("Access Token:" + access_token); 91 | res.status(200).json({access_token}) 92 | }) 93 | 94 | server.use(/^(?!\/auth).*$/, (req, res, next) => { 95 | if (req.headers.authorization === undefined || req.headers.authorization.split(' ')[0] !== 'Bearer') { 96 | const status = 401 97 | const message = 'Error in authorization format' 98 | res.status(status).json({status, message}) 99 | return 100 | } 101 | try { 102 | let verifyTokenResult; 103 | verifyTokenResult = verifyToken(req.headers.authorization.split(' ')[1]); 104 | 105 | if (verifyTokenResult instanceof Error) { 106 | const status = 401 107 | const message = 'Access token not provided' 108 | res.status(status).json({status, message}) 109 | return 110 | } 111 | next() 112 | } catch (err) { 113 | const status = 401 114 | const message = 'Error access_token is revoked' 115 | res.status(status).json({status, message}) 116 | } 117 | }) 118 | 119 | server.use(router) 120 | 121 | server.listen(8000, () => { 122 | console.log('Run Auth API Server') 123 | }) --------------------------------------------------------------------------------