Created
July 21, 2022 22:19
-
-
Save canterberry/36c60b89c4ead378587bb06fe7239e81 to your computer and use it in GitHub Desktop.
TWJ is JWT for Node.js apps. Here's how to use it.
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 { createSigner, createValidator, createVerifier } from 'twj/v0'; | |
import { generateKeyPairSync } from 'node:crypto'; | |
/** | |
* Generate a key-pair, if you don't already have one, as a JWK object. | |
* Here's how you can do that using native APIs provided by Node.js | |
* In production scenarios, you'll already have this somewhere under | |
* configuration management alongside your other secrets. | |
*/ | |
const { privateKey, publicKey } = generateKeyPairSync('ec', { | |
namedCurve: 'P-256', | |
privateKeyEncoding: { format: 'jwk' }, | |
publicKeyEncoding: { format: 'jwk' } | |
}); | |
/** | |
* NOTE: The keys we generated above do not have a `kid` property by default, | |
* so now would be a good time to generate one and sprinkle that in. | |
* Obviously, you'll want to do something more clever than what I've shown below. | |
* One idea is to hash the public key in JSON string format and use the hex encoding as the kid. | |
*/ | |
privateKey.kid = publicKey.kid = 'the-best-key-i-ever-did-make'; | |
/** | |
* The issuer will `sign` a set of JWT claims, using its private key, to produce a signed JWT token. | |
* The audience will `verify` that token using the issuer's public key, to extract the original JWT claims. | |
* Here, we initialize both of those functions. | |
* In this example, we'll play the role of both issuer and audience, so we can show how to initialize and use both. | |
*/ | |
const sign = createSigner({ key: privateKey }); | |
const verify = createVerifier({ key: publicKey }); | |
/** | |
* After a token is successfully verified, we still need to `validate` the JWT claims in that token. | |
* Here, we initialize that function with the configuration we'd like to use. | |
* Commented-out are some example options you can provide. | |
* If you provide no configuration options, only temporal claims (like exp and iat) are validated, using the system clock and a default clock tolerance of 30 seconds. | |
*/ | |
const validate = createValidator({ | |
// audiences: ['https://audience.example.com'], | |
// issuers: ['https://issuer.example.com'], | |
// clockToleranceSeconds: 30, | |
// currentTimeSeconds: () => Math.floor(new Date().getTime() / 1000) | |
}); | |
/** | |
* Alright, let's get to work! | |
* Here, we sign a simple set of claims including only a subject. | |
* This is where you'd sprinkle in any standard JWT claims you like, | |
* or add your own. | |
* Some ideas for claims you probably want to include: aud, iss, exp, iat, sub, scope | |
*/ | |
const token = await sign({ | |
sub: '[email protected]' | |
}); | |
// Let's have a look at the token! | |
console.log(token); | |
/* | |
* Now let's pretend we have received that token from a client (say, via an HTTP Authorization header) | |
* Here's how we extract the claims from it using the verifier we initialized earlier. | |
*/ | |
const claims = await verify(token); | |
// Let's have a look at those claims! | |
console.log(claims); | |
/** | |
* Now, let's validate those claims. | |
* Here is where we'll enforce some standard rules, per the validator's configuration. | |
* You're welcome to do any additional validation you'd like, or forego TWJ's validator | |
* altogether if you want to just do your own. | |
*/ | |
await validate(claims); | |
// Finally, let's just log a note that we're done. | |
console.log('OK'); | |
/** | |
* Congratulations! That's all there is to it! | |
* JWT isn't that hard, after all. | |
* If you're feeling good about that and thought it was interesting, | |
* you might want to explore more cryptography. | |
* The whole sign/verify bit is a common concept in "public key cryptography", | |
* also known as PKI. If that's new to you, and you want to learn more, I | |
* advise you to check out PGP (aka: GPG). That's another very common application | |
* of public/private key-pairs to sign and verify things. | |
* From there, check out Diffie-Hellman key exchange (aka: DH key exchange). | |
* That's how you can turn a public/private key-pair into a full-on encrypted | |
* communication channel, which is the underlying tech for a lot of secure tools | |
* we use everywhere, like TLS/HTTPS and SSH. Whoa! | |
*/ |
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
{ | |
"private": true, | |
"main": "main.mjs", | |
"module": "main.mjs", | |
"type": "module", | |
"scripts": { | |
"test": "node main.mjs" | |
}, | |
"dependencies": { | |
"twj": "^0.1.0" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment