Skip to content

Instantly share code, notes, and snippets.

@hgouveia
Last active July 25, 2018 09:04
Show Gist options
  • Save hgouveia/52febff5722e0e487e5347e52b1abbba to your computer and use it in GitHub Desktop.
Save hgouveia/52febff5722e0e487e5347e52b1abbba to your computer and use it in GitHub Desktop.
JWT nodejs very simple impl
/**
* Usage:
* const JWT = require('./JWT');
* const payload = {
* 'sub': 1234, // userid
* 'iat': Date().now(), // issued at
* 'exp': Math.floor(Date.now() / 1000) + 86400 // expiration time (1day = 86400)
* };
* const token = JWT.encode(payload, 'my_secret');
* console.log(token);
*/
'use strict';
const crypto = require('crypto');
export class JWTHelper {
/**
* Encode a JWT token
*
* @param {*} payload
* @param {*} secret
*/
static encode(payload, secret) {
const algorithm = 'HS256';
const header = {
typ: 'JWT',
alg: algorithm
};
const jwt = JWTHelper.__toB64(header) + '.' + JWTHelper.__toB64(payload);
return jwt + '.' + JWTHelper.__sign(jwt, secret);
}
static validate(token, secret) {
if (!token || !secret) {
return false;
}
const splitParts = token.split('.');
if (splitParts.length < 3) {
return false;
}
const [header, payload, signature] = splitParts;
return (signature === JWTHelper.__sign(header + '.' + payload, secret));
}
/**
* Decode a JWT token
*
* @static
* @param {string} token
* @throws Error
* @returns object|boolean
* @memberof JWTHelper
*/
static decode(token) {
if (!token || token === '') {
throw new Error('Token is empty');
}
const tokenParts = token.split('.');
// This token is invalid
if (tokenParts.length < 3) {
throw new Error('Token is invalid');
}
// 0 - header
// 1 - payload
// 2 - signature
// Decode from base64 to json string
let [header, payload, signature] = tokenParts
.map(part => new Buffer(part, 'base64').toString());
// convert the JSON string to object
// this will throw error if fail on parsing
// but we dont wrap into try/catch, so the user
// could catch it themself
header = JSON.parse(header);
payload = JSON.parse(payload);
return {
header,
payload,
signature
};
}
/**
* Checks if the token has expired
*
* @static
* @param {string} token
* @throws Error
* @returns boolean
* @memberof JWTHelper
*/
static hasTokenExpired(token) {
const decodedToken = this.decode(token);
const payload = decodedToken.payload;
/*
Payload
{
"iat": timestamp,
"exp": timestamp
}
*/
if (payload.hasOwnProperty("exp")) {
const currentTime = new Date().getTime();
const expTime = new Date(payload.exp * 1000).getTime();
return (currentTime > expTime)
}
return false;
}
/**
*
* @param {*} str
* @param {*} key
*/
static __sign(str, key) {
return crypto.createHmac('sha256', key).update(str).digest('base64');
}
/**
*
* @param {*} value
*/
static __toB64(value) {
return Buffer(JSON.stringify(value)).toString('base64');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment