Last active
August 22, 2023 21:51
-
-
Save ronnievsmith/b15bc38341b70e5e63da6327375555d0 to your computer and use it in GitHub Desktop.
JSON Web Signature (JWS) Token via Asymmetric RSA Key Pair (RSASSA-PKCS1-v1_5) Using Node.js Crypto Module
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Buffer } from 'node:buffer'; | |
import fs from "node:fs"; | |
import url from 'node:url'; | |
import path from "node:path"; | |
const {createSign, createVerify, generateKeyPairSync} = await import('node:crypto'); | |
var claims = {name:"Joe",roles:["member","admin"]}; | |
var { privateKey, publicKey } = generateKeyPairSync("rsa", { | |
modulusLength: 2048, | |
publicKeyEncoding: { | |
type: 'spki', | |
format: 'pem' | |
}, | |
privateKeyEncoding: { | |
type: 'pkcs8', | |
format: 'pem', | |
} | |
}); | |
(async function () { | |
let jws = await returnJWS(claims); | |
console.log("\x1b[37mYour JWS token is: " + consoleString(jws)); | |
console.log("Paste JSON Web Token In Terminal Then Press Enter.") | |
})(); | |
function returnJWS(claims){ | |
let headerObject = { | |
alg: 'RS256', | |
typ: 'JWT', | |
kid: 'public' | |
}; | |
let headerString = JSON.stringify(headerObject); | |
let encodedHeader = Buffer.from(headerString).toString('base64url'); | |
let payloadString = JSON.stringify(claims); | |
let encodedPayload = Buffer.from(payloadString).toString('base64url'); | |
const sign = createSign('SHA256'); | |
sign.write(encodedHeader + '.' + encodedPayload); | |
sign.end(); | |
let signature = sign.sign(privateKey, 'base64url'); | |
let jsonWebToken = encodedHeader + '.' + encodedPayload + '.' + signature; | |
return jsonWebToken; | |
} | |
function validateJWS(jwt){ | |
try { | |
let jwtParts = jwt.split('.'); | |
let jwtHeader = jwtParts[0]; | |
let jwtPayload = jwtParts[1]; | |
let jwtSignature = jwtParts[2]; | |
let valid = false; | |
let header = JSON.parse(Buffer.from(jwtHeader, 'base64url').toString('utf-8')); | |
let alg = header.alg; | |
if(alg === "RS256"){ // MUST verify alg is not set to none | |
let verify = createVerify('SHA256'); | |
verify.write(jwtHeader + '.' + jwtPayload); | |
verify.end(); | |
valid = verify.verify(publicKey, jwtSignature, 'base64url'); | |
if(valid){ | |
return JSON.parse(Buffer.from(jwtPayload, 'base64url').toString('utf-8')); | |
} else { | |
throw (error) | |
} | |
} else { | |
throw (error) | |
} | |
} catch (e) { | |
//console.log (e); | |
return "\x1b[31mInvalid Token!\x1b[37m"; | |
} | |
} | |
function generatePrivateKey (str) { | |
return new Promise(function(resolve, reject) { | |
try { | |
let key = createPrivateKey({ | |
key: str, | |
format: 'pem', | |
encoding: 'utf-8' | |
}) | |
resolve (key); | |
} catch (e) { | |
reject (e); | |
} | |
}); | |
} | |
function generatePublicKey (str) { | |
return new Promise(function(resolve, reject) { | |
try { | |
let key = createPublicKey({ | |
key: str, | |
format: 'pem', | |
encoding: 'utf-8' | |
}) | |
resolve (key); | |
} catch (e) { | |
reject (e); | |
} | |
}); | |
} | |
export default {returnJWS, validateJWS}; | |
process.stdin.setEncoding('utf8'); | |
process.stdin.on('readable', async () => { | |
let chunk; | |
while ((chunk = process.stdin.read()) !== null) { | |
console.log(await validateJWS(chunk)); | |
} | |
}); | |
function consoleString(token){ | |
let tokenParts = token.split(/(\.)/); | |
let colors = ["32m","31m","33m","34m","36m"]; | |
let color = "\x1b[X"; | |
let str = "" | |
tokenParts.forEach(function(part,index){ | |
if(part != "."){ | |
str += color.replace("X",colors.shift()) | |
} | |
str += part; | |
str += "\x1b[37m" | |
}) | |
return str; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment