mirror of
https://github.com/fullstack-cash/bch-api.git
synced 2026-09-22 17:22:04 -07:00
Created middleware to retrieve JWT token from header
This commit is contained in:
@@ -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())
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user