JWT Auto-Renewal Middleware for Express
Everything is explained down here but you can check it out in a better format on the wiki : Link to the Wiki
jwt-selfissuer works by renewing a previous expired token with a new one, and returning it on the response headers. It's born from the idea of having an easy way of issuing tokens with security and easiness. By using it you provide an easy and secure way of controlling user access.
It works by using Redis to store a hash which is directly linked with the previous used token, this way it manages to only issue a new token when the hash stored in it matches one of the already registered on Redis. It also provides an easy way to revoke access to determined devices as each device is linked to an unique UUID.
It works by checking the Authorization header on the requests, it will issue a new one depending on the previous one expiration time, it responses with an X-Token header whether it has expired or not, the only difference is that if it has expired the X-Token will be the new one.
First, let's install it by writting
npm install jwt-selfissuer
Once it has been installed, let's import it to the file where we want to mount the middleware
var jwt_issuer = require('jwt-selfissuer')
#Issuing proper tokens ##Requirements A Token must include the next parameters:
- Expire time
- A hash previously stored in Redis
To comply with the expiring time you just need to issue a token with a exp key on the payload. There are two ways of doing it using the package jsonwebtoken:
let payload = {username: "test"}
const expireAt = Math.round(new Date()/1000) + (15*60) //Expires in 15 minutes
payload.exp = expireAt
const token = jwt.sign(payload,key,options)
let payload = {username: "test"}
let options = {}
options.expiresIn = 15*60 //Expires in 15 minutes
const token = jwt.sign(payload,key,options)
The way explained here is the best way I could think of, but I'm totally open to change my mind.
First we need to create a random hash for it to be stored along the payload:
let hash = crypto.randomBytes(8)
hash = hash.toString('hex')
payload.hash = hash
Secondly we need to store this hash on redis along other info such related to the device
let device_uuid = crypto.randomBytes(32)
device_uuid = device_uuid.toString('hex')
client.multi()
.hset(username+"_devices",device_uuid,JSON.stringify(device_info))
.hset(username+"_hashes",device_uuid,hash)
.exec((err,info) => {
if(err) console.log(err)
})
We are generating an UUID which is related to every device
There are multiples way of doing it, but here I'm going to explain the easiest one:
const key = "ThisIsTheKey"
var redis = require('redis')
client = redis.createClient()
const verification_options = {ignoreExpiration:true}
The last one paramater are the signing options for the token. Here you can change when the token Expires. (Optional)
const signing_options = {expiresIn:900}
var issuerMiddleware = jwt_issuer(key, client, verification_options, signing_options)
It is very simple, you just need to throw the previous declared variable into the endpoint that you want:
router.post('/user/info',issuerMiddleware,(req,res,next) => {
res.send(req.info.username)
})
Everything stored in the token payload will be accessible to you in req.info Just like:
const info = req.info
console.log(info) //This should print everyhing stored in your jwt