
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

An async implementation of JSON Web Tokens (JWT).
This implementation was developed against draft-ietf-oauth-json-web-token-32. Note that this library leverages core node modules to implement the JWT spec. The only dependency is lodash, which is used to implement some conveniences.
In my search I found that not all node JWT implementations were built with async first in mind. Additionally I wanted something that allowed for more flexability, but was still able to do the heavy lifting.
It's interesting to note that Node's Crypto.create methods are all synchronous. However the writeable streams to these methods are asynchronous. That means, with this library, the data you want to sign will be asynchronously streamed to the relevant crypto methods. The crypto methods themselves do not perform any heavy crypto computation, therefore its quite fast.
$ npm install jwt-async
$ npm test
var JWT = require('jwt-async');
// Create jwt instance
// Defaults to HS256 algorithm
var jwt = new JWT();
jwt.setSecret('secret');
// Sign the jwt
jwt.sign({someClaim: 'data'}, function (err, data) {
if (err) console.log(err);
// Print signed JWT
// Paste it into http://www.jwt.io
console.log(data);
// Verify it
jwt.verify(data, function (err, data) {
if (err) console.log(err);
// Print the verified JWT
// This is an object
console.log(data);
});
});
For sake of claity, the options hash is used to set the jwt instance up with some boilerplate. Meaning, when signing or verifying it will use the options defined. These can be changed via instance methods documented below. ie jwt.setSecret, jwt.setPrivateKey, jwt.setValidations, jwt.setClaims, etc.
var JWT = require('jwt-async');
var options = {
// Default crypto per sign
crypto: {
algorithm: 'HS512',
secret: 'secret'
},
// Default claims per sign
claims: {
// Automatically set 'Issued At' if true (epoch), or set to a number
iat: true,
// Set 'Not Before' claim
nbf: Math.floor(Date.now() / 1000) - 60,
// Set 'Expiration' claim
exp: Math.floor(Date.now() / 1000) + 60,
// Set a custom claim
custom: 'this is a custom claim'
},
// Default validations per verify
validations: {
custom: function (claims, next) {
// Do custom validation of claims
// IE verify audience with database, etc
if (claims.custom === 'this is a custom claim') {
next();
} else {
next(new Error('BOOM'));
}
},
exp: true,
nbf: true
}
};
// Create jwt instance
var jwt = new JWT(options);
// More claims that will be merged with the default options
// These will not persist since we're sending them directly to the sign method
var moreClaims = {
anotherField: 'this is another field'
}
// Sign the jwt
jwt.sign(moreClaims, function (err, data) {
if (err) console.log(err);
// Print signed JWT
// Paste it into http://www.jwt.io
console.log(data);
// Verify it
jwt.verify(data, function (err, data) {
if (err) console.log(err);
// Print the verified JWT
// This is an object
console.log(data);
});
});
If you don't like callbacks, then feel free to use promises. Here's how you can use this library with a promise library such as bluebird.
var JWT = require('jwt-async');
var BPromise = require('bluebird');
var jwt = BPromise.promisifyAll(new JWT());
jwt.setSecret('secret');
jwt.signAsync()
.then(function (signed) {
return jwt.verifyAsync(signed);
})
.then(function (claims) {
console.log(claims);
})
.catch(JWT.JWTError, function (e) {
console.log(e);
});
The JWT constructor can take an optional options hash defining some boiler plate for the instance returned. Once the instance is created, these options can be easily changed by executed the appropriate instance method. Without an options hash the JWT instance returned will default to HS256 (HMAC) JWT signing.
options
The only default set, without options, is the algorithm. Expect everything else either to be not set or set to false. Also, if its not obvious, claims are for the signing process and validations are for the verify process.
HS*, this is the secret used for the symmetric signingRS*, ES* this is the private key used for signing JWT'sRS*, ES* this is the public key used for verifying JWT'sWithout options
var JWT = require('jwt-async');
var jwt = new JWT;
With options; see above for full example
var JWT = require('jwt-async');
var jwt = new JWT(options);
claims
jwt.setClaims.callback
// Without a claims object
jwt.sign(null, function (err, data) {
// Log out signed JWT
console.log(data);
});
// With a claims object to be used for this signing
jwt.sign({customClaim: 'this is a custom claim'}, function (err, data) {
// Log out signed JWT
console.log(data);
});
// Enable iat
jwt.sign({iat: true}, function (err, data) {
// Log out signed JWT
console.log(data);
});
// Disable iat and add nbf
jwt.sign({iat: false, nbf: 1419405977}, function (err, data) {
// Log out signed JWT
console.log(data);
});
encodedJWT
callback
jwt.verify(data, function (err, data) {
// log Error object
if (err) console.log(err);
// log decoded and verified JWT object
console.log(data);
});
Note that validations are only processed AFTER a jwt is successfully verified. IE it was verified against the secret or public key.
validations
(object) - Object of validations to be set on the instance.
var validations = {
custom: function (claims, callback) {
// Custom logic here, return an error to fail the validation
if (claims.customClaim === 10) callback(new Error('This is bad!');
// Return successful
callback();
},
nbf: true,
exp: true
};
jwt.setValidations(validations);
key
var privateKey = fs.readFileSync('ec256-private.pem');
jwt.setPrivateKey(privateKey);
key
var publicKey = fs.readFileSync('ec256-public.pem');
jwt.setPrivateKey(publicKey);
algorithm
jwt.setAlgorithm('ES512');
claims
var claims = {
// If iat is set to true, an epoch date will be generated automatically.
iat: true,
customClaim: 'this is a custom claim'
};
jwt.setClaims(claims);
For methods that are callback based an error will be set on callback if neccessary.
JWTError is typically raised for generic type of error events. IE you tried to sign a JWT with algorithm ES256, but you don't have a privateKey set.
JWTValidationError is raised when a JWT fails the basic validation process. IE either the library wasn't able to verify that the JWT signed correctly, it was tampered with, unparseable, etc.
JWTExpiredError is raised when the current time is after the JWT claims exp time. This error also exposes an expiredAt property on the error object that reflects when the JWT expired. Note that you must have exp validations enabled.
JWTInvalidBeforeTimeError is raised when the current time is before the JWT claims nbf time. This error also exposes an invalidBefore property on the error object that reflects when the JWT will be valid after. Note that you must have nbf validations enabled.
| Algorithm | Description | Supported? |
|---|---|---|
| none | No digital signature or MAC performed | ✓ |
| HS256 | HMAC using SHA-256 | ✓ |
| HS384 | HMAC using SHA-384 | ✓ |
| HS512 | HMAC using SHA-512 | ✓ |
| RS256 | RSASSA-PKCS-v1_5 using SHA-256 | ✓ |
| RS384 | RSASSA-PKCS-v1_5 using SHA-384 | ✓ |
| RS512 | RSASSA-PKCS-v1_5 using SHA-512 | ✓ |
| ES256 | ECDSA using P-256 and SHA-256 | ✓ |
| ES384 | ECDSA using P-384 and SHA-384 | ✓ |
| ES512 | ECDSA using P-521 and SHA-512 | ✓ |
| PS256 | RSASSA-PSS using SHA-256 and MGF1 with SHA-256 | ✖ |
| PS384 | RSASSA-PSS using SHA-384 and MGF1 with SHA-384 | ✖ |
| PS512 | RSASSA-PSS using SHA-512 and MGF1 with SHA-512 | ✖ |
X.509 certificate support is not implemented
MIT
FAQs
JSON Web Token (JWT) with asynchronicity
We found that jwt-async demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.