Last active
August 23, 2023 03:36
-
-
Save ronnievsmith/5bab7f096eb401b5353ad986ed5cd260 to your computer and use it in GitHub Desktop.
JSON Web Signature (JWS) Token via Elliptic Curve Digital Signature Algorithm (ECDSA) Using P-256 and SHA-256 w Node.js Crypto Module
This file contains 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("ec", { | |
namedCurve: 'secp256k1', | |
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: 'ES256', | |
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 === "ES256"){ // 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