Created
April 26, 2023 02:42
-
-
Save Lohann/9a65b68890611cac436c1863a7d28e9d to your computer and use it in GitHub Desktop.
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
const webcrypto = require('crypto').webcrypto.subtle; | |
const enc = new TextEncoder(); | |
function bytesToBase64url(bytes) { | |
return Buffer.from(bytes).toString('base64url'); | |
} | |
function jsonToBase64url(obj) { | |
const bytes = enc.encode(JSON.stringify(obj)); | |
return bytesToBase64url(bytes); | |
} | |
/** | |
* Verifies the signature of a JWT. | |
*/ | |
async function verifyJWT(jwt, publicKey) { | |
const [header, payload, signature] = jwt.split('.'); | |
const body = header + '.' + payload; | |
// Import the public key from JWK format | |
const pubkey = await webcrypto.importKey( | |
'jwk', | |
publicKey, | |
{ | |
name: "RSASSA-PKCS1-v1_5", | |
namedCurve: publicKey.crv, | |
hash: "SHA-256", | |
}, | |
true, | |
publicKey.key_ops, | |
); | |
// Verify the signature | |
return await webcrypto.verify( | |
{ | |
name: "RSASSA-PKCS1-v1_5", | |
hash: { name: "SHA-256" }, | |
}, | |
pubkey, | |
Buffer.from(signature, 'base64url'), | |
enc.encode(body), | |
); | |
} | |
/** | |
* Sign and return JWT | |
*/ | |
async function signJWT(header, payload, jwkPrivateKey) { | |
const headerbase64 = jsonToBase64url(header); | |
const payloadbase64 = jsonToBase64url(payload); | |
const body = headerbase64 + '.' + payloadbase64; | |
// Import the public key from JWK format | |
const privateKey = await webcrypto.importKey( | |
'jwk', | |
jwkPrivateKey, | |
{ | |
name: "RSASSA-PKCS1-v1_5", | |
namedCurve: jwkPrivateKey.crv, | |
hash: "SHA-256", | |
}, | |
true, | |
jwkPrivateKey.key_ops, | |
); | |
// Sign JWT | |
const signature = await webcrypto.sign( | |
{ | |
name: "RSASSA-PKCS1-v1_5", | |
hash: { name: "SHA-256" }, | |
}, | |
privateKey, | |
enc.encode(body), | |
); | |
const signatureBase64 = bytesToBase64url(signature); | |
const jwt = body + '.' + signatureBase64; | |
return jwt; | |
} | |
async function main() { | |
// Generate a new keypair | |
const keyPair = await webcrypto.generateKey( | |
{ | |
name: "RSASSA-PKCS1-v1_5", | |
modulusLength: 4096, | |
publicExponent: new Uint8Array([1, 0, 1]), | |
hash: "SHA-256", | |
}, | |
true, | |
["sign", "verify"] | |
); | |
// Export the public key to JWK format | |
const jwkPrivateKey = await webcrypto.exportKey('jwk', keyPair.privateKey); | |
const jwkPublicKey = await webcrypto.exportKey('jwk', keyPair.publicKey); | |
console.log('PrivateKey:') | |
console.log(JSON.stringify(jwkPrivateKey)); | |
console.log('\nPublicKey:') | |
console.log(JSON.stringify(jwkPublicKey)); | |
// JWT Header and Payload | |
const header = { | |
"kid": "s16tqSm88pDJ8TfB_7kHKPRAPF85wUDTlmyo9ILTe7s", | |
"alg": "RS256" | |
}; | |
const payload = { | |
"sub": "[email protected]", | |
"name": "Friendly Lynx", | |
"email": "[email protected]", | |
"iss": "https://pk-demo.okta.com/oauth2/default", | |
"aud": "LbSvMcaJ6iomfl7PcjSkmFSt", | |
"iat": 1682467047, | |
"exp": 1685059047, | |
"amr": [ | |
"pwd" | |
] | |
}; | |
// Sign JWT | |
const jwt = await signJWT(header, payload, jwkPrivateKey); | |
console.log('\nJWT:') | |
console.log(jwt); | |
// Verify signature | |
console.log('\nJWT Signature Verification:') | |
console.log(await verifyJWT(jwt, jwkPublicKey)); | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment