twj
v0.1.0
Published
A minimal suite of functions for handling JWT tokens. Cryptographic signing, cryptographic verification, and JWT standard claims validation.
Readme
TWJ
Why?
Because jose -- the only other viable choice -- is unstable, whimsically rewritten, poorly organized, and bloated.
Design Goals
TWJ aims to be production-grade software, suitable for real-world commercial workloads of millions of users authenticating with JWT tokens.
- Backwards compatibility / stable interface
- Deterministic execution
- High reliability
- Fast performance
- Laser-focused on real-world usage
- Zero dependencies
- Lightweight implementation
- Readable code, suitable for learning and self-education
- Secure and trustworthy
Installing
Install twj using your favorite npm package manager.
$ npm install --save twjUsage
createSigner() -- Signing a set of JWT claims
Common JWT claims include sub, iss, iat, exp, aud.
You can pass any claims to the signer you want. There is no
enforcement or validation of claims while signing.
First off, here is how to import the module for creating a signer:
import { createSigner } from 'twj';Once you have createSigner(), you can use it to create a sign() function:
const sign = createSigner({
key: {/* ...your private key in JWK format */}
});Recommended: Include a "kid" property in your private key. If present, this property will be included in the token header, enabling dynamic key lookup during token verification.
Now that you have a sign() function, you can begin using it to sign JWT
claims:
const token = await sign({/* ...any JWT claims you want signed...*/});The result is a signed JWT token string with the given claims.
createVerifier() -- Verifying a signed JWT token and extracting its claims
import { createVerifier } from 'twj';Once you have createVerifier(), you can use it to create a verify()
function:
const verify = createVerifier({
key: {
/* ...a public key, in JWK format, trusted for signing legitimate tokens */
}
});Alternatively, key can be an asynchronous function that, given the
deserialized token header and payload objects, resolves to the corresponding
public key, in JWK format, to use for verifying that token (or rejects if no
trusted key can be found):
const verify = createVerifier({
key: async ({ header, payload }) => {
// Find a trusted public key to use to verify this token.
// If no trusted public key can be found, then reject/throw.
// Else, resolve with the trusted public key as a JWK object.
}
});Finally, once you have a verify() function, you can begin using it to verify
tokens:
const claims = await verify(token);Important: The
verify()function DOES NOT enforce JWT claims. It just ensures the token is authentic and signed by a trusted issuer. You probably still want to usevalidate()as well to enforce claims of interest.
createValidator() -- Validating JWT claims
JWT claim validation occurs after verifying the token is signed by a trusted issuer. Therefore, the claims in the token are known to have been true at some point in the past. Validation is the phase where these claims are examined to determine if they are still true, and if they are true for this context.
Some examples of validation rules include:
Ensuring that if the token claims to expire, that it is not currently expired.
Ensuring that if the token claims when it was issued, that it was not issued in the future.
Ensuring that if the token claims an audience, that we identify with that audience.
Ensuring that if the token claims an issuer, that we trust that issuer.
Let's import the createValidator() module:
import { createValidator } from 'twj';Now, let's initialize it with how we'd like to validate our claims:
const validate = createValidator({
audiences: [
'https://example.com'
]
});In this example, we're configuring our validator to reject any token whose
aud claim is not 'https://example.com'. Any exp and/or iat claims,
if present, will be validated using the default system clock and default clock
drift tolerance. The iss claim, if present, will be ignored, because there
are no allow-listed issuers in the configuration object.
options.audiences(string[]) - A set of values to accept for a token'saudclaim.options.clockToleranceSeconds(Number) - How many seconds to tolerate during temporal validation onexpandiatclaims. Defaults to30.options.currentTimeSeconds(function():Number) - A function that returns the current time in seconds as a whole number relative to Unix epoch. Used for temporal validation onexpandiatclaims. Defaults to using the system clock.options.issuers(string[]) - A set of values to accept for a token'sissclaim.
