-
Initialise repository
yarn init
-
Initialise repository with express and body-parser
yarn add express body-parser
-
Add nodemon module
yarn add nodemon --dev
-
Create server.js
const express = require('express')
const bodyParser = require('body-parser')
const server = express()
// Middleware Plugins
server.use(bodyParser.json())
// Routes
server.use('/', [
// require('./routes/whatever')
])
// Start the server
server.listen(7000, error => {
if (error) console.error('Error starting', error)
else console.log('Started at http://localhost:7000')
})
- Add scripts in
package.json
"scripts": {
"dev": "nodemon server.js",
"seed": "node models/seeds.js",
"drop": "node models/drop.js",
"reset": "npm run drop && npm run seed"
}
-
Add mongoose module
yarn add mongoose
-
Add
models\init.js
const mongoose = require('mongoose')
// Use the Promise functionality built into Node.js
mongoose.Promise = global.Promise
// Connect to our local database
mongoose
.connect('mongodb://localhost/secret-documents', { useMongoClient: true })
.then(() => {
console.log('Successfully connected to database')
})
.catch(error => {
// If there was an error connecting to the database
if (error) console.log('Error connecting to MongoDB database', error)
})
module.exports = mongoose
- Create
models\Document.js
const mongoose = require('./init')
const Document = mongoose.model('Document', {
title: String, // e.g. Sokovia Accords
content: String // e.g. The Sokovia Accords. Approved by 117 countries, it states that the Avengers shall no longer be a private organization. Instead, they'll operate under the supervision of a United Nations panel, only when and if that panel deems it necessary.
})
module.exports = Document
- Create
models\seeds.js
const Document = require('./Document')
Document.create([
{
title: 'Sokovia Accords',
content:
"The Sokovia Accords. Approved by 117 countries, it states that the Avengers shall no longer be a private organization. Instead, they'll operate under the supervision of a United Nations panel, only when and if that panel deems it necessary."
},
{
title: 'Impact on S.H.I.E.L.D.',
content:
'I\'m here because the President sent me. The Sokovia Accords are the law of the land now and he\'s concerned you might have some undocumented "assets" working for you.'
},
{
title: 'Regulations',
content:
'Any enhanced individuals who agree to sign must register with the United Nations and provide biometric data such as fingerprints and DNA samples.'
}
])
.then(documents => {
console.log('Created documents', documents)
process.exit()
})
.catch(error => {
console.error('Error creating documents', error)
})
- Create
models\drop.js
const Document = require('./Document')
Document.deleteMany().then(() => {
console.log('Deleted documents')
process.exit()
})
-
Create
routes\document.js
using boilerplate
(or runSkafold Document
with Skafold app) -
Add route for document in server.js
// Routes
server.use('/', [
require('./routes/document')
])
- Create
check\1.http
and test the app
GET http://localhost:7000/document
-
Add passport middleware
yarn add passport passport-local passport-local-mongoose
-
Add passport-jwt middleware
yarn add passport-jwt
-
Add User model with Passport plugin (
models\User.js
)
const mongoose = require('./init')
const passportLocalMongoose = require('passport-local-mongoose')
const userSchema = new mongoose.Schema({
firstName: String,
lastName: String
})
// Add passport middleware to User Schema
userSchema.plugin(passportLocalMongoose, {
usernameField: 'email', // Use email, not the default 'username'
usernameLowerCase: true, // Ensure that all emails are lowercase
session: false // Disable sessions as we'll use JWTs
})
const User = mongoose.model('User', userSchema)
module.exports = User
-
Generate a jwtSecret token using console
openssl rand -base64 48
-
Add helper for middleware
middleware\auth.js
const passport = require('passport')
const JWT = require('jsonwebtoken')
const PassportJwt = require('passport-jwt')
const User = require('../models/User')
// These should be in .env
// secret (generated using `openssl rand -base64 48` from console)
const jwtSecret =
'QOOC3nUVl9yTZiH2F0VYjOJhwm2ZkyBjWK7Mzo4bH54cNBBUQmp262S0Tx1eBBTT'
const jwtAlgorithm = 'HS256'
const jwtExpiresIn = '7 days'
passport.use(User.createStrategy())
function register(req, res, next) {
const user = new User({
email: req.body.email,
firstName: req.body.firstName,
lastName: req.body.lastName
})
// Create the user with the specified password
User.register(user, req.body.password, (error, user) => {
if (error) {
// Our register middleware failed
next(error)
return
}
// Store user so we can access it in our handler
req.user = user
// Success!
next()
})
}
passport.use(
new PassportJwt.Strategy(
// Options
{
// Where will the JWT be passed in the HTTP request?
// e.g. Authorization: Bearer xxxxxxxxxx
jwtFromRequest: PassportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),
// What is the secret
secretOrKey: jwtSecret,
// What algorithm(s) were used to sign it?
algorithms: [jwtAlgorithm]
},
// When we have a verified token
(payload, done) => {
// Find the real user from our database using the `id` in the JWT
User.findById(payload.sub)
.then(user => {
// If user was found with this id
if (user) {
done(null, user)
} else {
// If not user was found
done(null, false)
}
})
.catch(error => {
// If there was failure
done(error, false)
})
}
)
)
function signJWTForUser(req, res) {
// Get the user (either just signed in or signed up)
const user = req.user
// Create a signed token
const token = JWT.sign(
// payload
{
email: user.email
},
// secret
jwtSecret,
{
algorithm: jwtAlgorithm,
expiresIn: jwtExpiresIn,
subject: user._id.toString()
}
)
// Send the token
res.json({ token })
}
module.exports = {
initialize: passport.initialize(),
register,
signIn: passport.authenticate('local', { session: false }),
requireJWT: passport.authenticate('jwt', { session: false }),
signJWTForUser
}
- Add route for auth (
routes\auth.js
)
const express = require('express')
const authMiddleware = require('../middleware/auth')
const router = express.Router()
// Register
router.post(
'/auth/register',
// middleware that handles the registration process
authMiddleware.register,
// json handler
authMiddleware.signJWTForUser
)
// Sign in
router.post(
'/auth',
// middleware that handles the sign in process
authMiddleware.signIn,
// json handler
authMiddleware.signJWTForUser
)
module.exports = router
- Add route for auth in server.js
// Routes
server.use('/', [
require('./routes/auth'),
require('./routes/document')
])
- Update document route to use JWT middleware
const authMiddleware = require('../middleware/auth')
- Add
authMiddleware.requireJWT
as 2nd argument to every route (see example below)
// GET - Read all document
router.get('/documents', authMiddleware.requireJWT, (req, res) => {
Document.find()
// Once it has loaded these documents
.then(documents => {
// Send them back as the response
res.json(documents)
})
.catch(error => {
res.status(400).json({ error: error.message })
})
})
- Update
check\1.http
and test the auth routes
### Registration
POST http://localhost:7000/auth/register
Content-Type: application/json
{
"email": "glenn.dimaliwat@gmailcom",
"firstName": "Glenn",
"lastName" : "Dimaliwat",
"password" : "password123"
}
### Sign In
POST http://localhost:7000/auth/
Content-Type: application/json
{
"email": "glenn.dimaliwat@gmailcom",
"password" : "password123"
}
- Also in
check\1.http
, Copy the token after successful sign in and test the product routes with JWT authentication
###
GET http://localhost:7000/documents
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImdsZW5uLmRpbWFsaXdhdEBnbWFpbGNvbSIsImlhdCI6MTUxMjU2MzQ1MCwiZXhwIjoxNTEzMTY4MjUwLCJzdWIiOiI1YTI3ZTJhNTI0NjQ1NTFlYTAyOTE1YzQifQ.QKQLXZgcYNS_57E9fm4C12IAKUXnN9hChmkD36PrZi4
###
GET http://localhost:7000/documents/5a27db9a6c728b182aa14b41
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImdsZW5uLmRpbWFsaXdhdEBnbWFpbGNvbSIsImlhdCI6MTUxMjU2MzQ1MCwiZXhwIjoxNTEzMTY4MjUwLCJzdWIiOiI1YTI3ZTJhNTI0NjQ1NTFlYTAyOTE1YzQifQ.QKQLXZgcYNS_57E9fm4C12IAKUXnN9hChmkD36PrZi4