Created middleware to retrieve JWT token from header

This commit is contained in:
Chris Troutner
2019-10-20 11:55:46 -07:00
parent 532f06cec1
commit 4032e66be3
7 changed files with 436 additions and 184 deletions
+6
View File
@@ -15,7 +15,10 @@ const helmet = require("helmet")
const debug = require("debug")("rest-cloud:server")
const http = require("http")
const cors = require("cors")
// Auth and rate limiting middleware libraries.
const AuthMW = require("./middleware/auth")
const jwtAuth = require("./middleware/jwt-auth")
// v2
const indexV2 = require("./routes/v2/index")
@@ -88,6 +91,9 @@ app.use(express.static(path.join(__dirname, "public")))
const v2prefix = "v2"
const v3prefix = "v3"
// Inspect the header for a JWT token.
app.use(`/${v3prefix}/`, jwtAuth.getTokenFromHeaders)
// Instantiate the authorization middleware, used to implement pro-tier rate limiting.
const auth = new AuthMW()
app.use(`/${v2prefix}/`, auth.mw())
+43
View File
@@ -1,6 +1,13 @@
/*
Handle authorization for bypassing rate limits.
1) Default is 'Anonymous Authentication', which unlocks the freemimum tier by
default.
2) Hard-coded 'Basic Authentication' is a token that does not expire and is
provided to buisiness partners.
3) JWT-based 'Local Authentication' is used for normal users that pay to
access the premium pro-tier services.
This file uses the passport npm library to check the header of each REST API
call for the prescence of a Basic authorization header:
https://en.wikipedia.org/wiki/Basic_access_authentication
@@ -14,7 +21,9 @@
const passport = require("passport")
const BasicStrategy = require("passport-http").BasicStrategy
const AnonymousStrategy = require("passport-anonymous")
const LocalStrategy = require("passport-local")
const wlogger = require("../util/winston-logging")
const axios = require("axios")
// Used for debugging and iterrogating JS objects.
const util = require("util")
@@ -88,6 +97,40 @@ class AuthMW {
return done(null, true)
})
)
// JWT token based authentication.
passport.use(
new LocalStrategy(
{
usernameField: "user[email]",
passwordField: "user[password]",
passReqToCallback: true,
session: false
},
async (req, email, password, done) => {
console.log(`Checking against local strategy.`)
const userData = {}
const isValid = true
// Lookup the user from the database.
// const userData = await userDB.findByEmail(email)
//console.log(`userData: ${util.inspect(userDataRaw)}`)
// Hash the password and see if it matches the saved hash.
// const isValid = jwt.validatePassword(userData, password)
if (isValid) {
//console.log(`Passwords match!`)
return done(null, userData)
}
return done(null, false, {
errors: { "email or password": "is invalid" }
})
}
)
)
}
// Middleware called by the route.
+43
View File
@@ -0,0 +1,43 @@
/*
This middleware inspects the request header for a JWT token.
If found, will populate req.locals.jwtToken with the JWT token.
*/
"use strict"
// This function searches the header for the a JWT token in the authorization header.
// If one is found, this middleware passes the JWT token through the
// req.locals.jwtToken property.
const getTokenFromHeaders = (req, res, next) => {
try {
// console.log(`getTokenFromHeaders2: Searching headers for a JWT token.`)
// console.log(`req.headers: `, req.headers)
// If the authorization header exists.
if (req.headers.authorization) {
const authStr = req.headers.authorization
// If the header is proceeded by the word 'Token'
if (authStr.split(" ")[0] === "Token") {
const token = authStr.split(" ")[1]
// console.log(`JWT found: ${token}`)
// Create the req.locals property if it does not yet exist.
if (!req.locals) req.locals = {}
req.locals.jwtToken = token
}
}
} catch (err) {
console.log(`Error in getTokenFromHeaders2: `, err)
}
next()
}
const jwtAuth = {
getTokenFromHeaders
}
module.exports = jwtAuth
+19 -2
View File
@@ -24,11 +24,28 @@ const PRO_RPM = 10 * maxRequests
const uniqueRateLimits = {}
const routeRateLimit = function(req, res, next) {
// Disable rate limiting if 0 passed from RATE_LIMIT_MAX_REQUESTS
if (maxRequests === 0) return next()
// Create a res.locals object if not passed in.
if (!req.locals) req.locals = {}
// Disable rate limiting if 0 passed from RATE_LIMIT_MAX_REQUESTS
if (maxRequests === 0) return next()
if (req.locals.jwtToken)
console.log(`req.locals.jwtToken: ${req.locals.jwtToken}`)
// If no JWT token was provided, skip
if (req.payload)
console.log(`req.payload: ${JSON.stringify(req.payload, null, 2)}`)
// // Unlock the pro-tier rate limits if the user passed in a valid JWT token.
// if (!proRateLimits) {
// const user = await getUserFromJWT(req)
//
// // Enable pro-tier rate limits for this user.
// if(user) {
// console.log(`${user.email} (${user.id}) passed in valid JWT`)
// proRateLimits = true
// }
// }
// Current route
const rateLimitTier = req.locals.proLimit ? "PRO" : "BASIC"