Giter Site home page Giter Site logo

node-jsonwebtoken's Introduction

jsonwebtoken

Build Dependency
Build Status Dependency Status

An implementation of JSON Web Tokens.

This was developed against draft-ietf-oauth-json-web-token-08. It makes use of node-jws

Install

$ npm install jsonwebtoken

Migration notes

Usage

jwt.sign(payload, secretOrPrivateKey, [options, callback])

(Asynchronous) If a callback is supplied, the callback is called with the err or the JWT.

(Synchronous) Returns the JsonWebToken as string

payload could be an object literal, buffer or string representing valid JSON.

Please note that exp or any other claim is only set if the payload is an object literal. Buffer or string payloads are not checked for JSON validity.

If payload is not a buffer or a string, it will be coerced into a string using JSON.stringify.

secretOrPrivateKey is a string (utf-8 encoded), buffer, object, or KeyObject containing either the secret for HMAC algorithms or the PEM encoded private key for RSA and ECDSA. In case of a private key with passphrase an object { key, passphrase } can be used (based on crypto documentation), in this case be sure you pass the algorithm option. When signing with RSA algorithms the minimum modulus length is 2048 except when the allowInsecureKeySizes option is set to true. Private keys below this size will be rejected with an error.

options:

  • algorithm (default: HS256)
  • expiresIn: expressed in seconds or a string describing a time span vercel/ms.

    Eg: 60, "2 days", "10h", "7d". A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default ("120" is equal to "120ms").

  • notBefore: expressed in seconds or a string describing a time span vercel/ms.

    Eg: 60, "2 days", "10h", "7d". A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default ("120" is equal to "120ms").

  • audience
  • issuer
  • jwtid
  • subject
  • noTimestamp
  • header
  • keyid
  • mutatePayload: if true, the sign function will modify the payload object directly. This is useful if you need a raw reference to the payload after claims have been applied to it but before it has been encoded into a token.
  • allowInsecureKeySizes: if true allows private keys with a modulus below 2048 to be used for RSA
  • allowInvalidAsymmetricKeyTypes: if true, allows asymmetric keys which do not match the specified algorithm. This option is intended only for backwards compatability and should be avoided.

There are no default values for expiresIn, notBefore, audience, subject, issuer. These claims can also be provided in the payload directly with exp, nbf, aud, sub and iss respectively, but you can't include in both places.

Remember that exp, nbf and iat are NumericDate, see related Token Expiration (exp claim)

The header can be customized via the options.header object.

Generated jwts will include an iat (issued at) claim by default unless noTimestamp is specified. If iat is inserted in the payload, it will be used instead of the real timestamp for calculating other things like exp given a timespan in options.expiresIn.

Synchronous Sign with default (HMAC SHA256)

var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');

Synchronous Sign with RSA SHA256

// sign with RSA SHA256
var privateKey = fs.readFileSync('private.key');
var token = jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' });

Sign asynchronously

jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' }, function(err, token) {
  console.log(token);
});

Backdate a jwt 30 seconds

var older_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh');

Token Expiration (exp claim)

The standard for JWT defines an exp claim for expiration. The expiration is represented as a NumericDate:

A JSON numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap seconds. This is equivalent to the IEEE Std 1003.1, 2013 Edition [POSIX.1] definition "Seconds Since the Epoch", in which each day is accounted for by exactly 86400 seconds, other than that non-integer values can be represented. See RFC 3339 [RFC3339] for details regarding date/times in general and UTC in particular.

This means that the exp field should contain the number of seconds since the epoch.

Signing a token with 1 hour of expiration:

jwt.sign({
  exp: Math.floor(Date.now() / 1000) + (60 * 60),
  data: 'foobar'
}, 'secret');

Another way to generate a token like this with this library is:

jwt.sign({
  data: 'foobar'
}, 'secret', { expiresIn: 60 * 60 });

//or even better:

jwt.sign({
  data: 'foobar'
}, 'secret', { expiresIn: '1h' });

jwt.verify(token, secretOrPublicKey, [options, callback])

(Asynchronous) If a callback is supplied, function acts asynchronously. The callback is called with the decoded payload if the signature is valid and optional expiration, audience, or issuer are valid. If not, it will be called with the error.

(Synchronous) If a callback is not supplied, function acts synchronously. Returns the payload decoded if the signature is valid and optional expiration, audience, or issuer are valid. If not, it will throw the error.

Warning: When the token comes from an untrusted source (e.g. user input or external requests), the returned decoded payload should be treated like any other user input; please make sure to sanitize and only work with properties that are expected

token is the JsonWebToken string

secretOrPublicKey is a string (utf-8 encoded), buffer, or KeyObject containing either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA. If jwt.verify is called asynchronous, secretOrPublicKey can be a function that should fetch the secret or public key. See below for a detailed example

As mentioned in this comment, there are other libraries that expect base64 encoded secrets (random bytes encoded using base64), if that is your case you can pass Buffer.from(secret, 'base64'), by doing this the secret will be decoded using base64 and the token verification will use the original random bytes.

options

  • algorithms: List of strings with the names of the allowed algorithms. For instance, ["HS256", "HS384"].

    If not specified a defaults will be used based on the type of key provided

    • secret - ['HS256', 'HS384', 'HS512']
    • rsa - ['RS256', 'RS384', 'RS512']
    • ec - ['ES256', 'ES384', 'ES512']
    • default - ['RS256', 'RS384', 'RS512']
  • audience: if you want to check audience (aud), provide a value here. The audience can be checked against a string, a regular expression or a list of strings and/or regular expressions.

    Eg: "urn:foo", /urn:f[o]{2}/, [/urn:f[o]{2}/, "urn:bar"]

  • complete: return an object with the decoded { payload, header, signature } instead of only the usual content of the payload.
  • issuer (optional): string or array of strings of valid values for the iss field.
  • jwtid (optional): if you want to check JWT ID (jti), provide a string value here.
  • ignoreExpiration: if true do not validate the expiration of the token.
  • ignoreNotBefore...
  • subject: if you want to check subject (sub), provide a value here
  • clockTolerance: number of seconds to tolerate when checking the nbf and exp claims, to deal with small clock differences among different servers
  • maxAge: the maximum allowed age for tokens to still be valid. It is expressed in seconds or a string describing a time span vercel/ms.

    Eg: 1000, "2 days", "10h", "7d". A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default ("120" is equal to "120ms").

  • clockTimestamp: the time in seconds that should be used as the current time for all necessary comparisons.
  • nonce: if you want to check nonce claim, provide a string value here. It is used on Open ID for the ID Tokens. (Open ID implementation notes)
  • allowInvalidAsymmetricKeyTypes: if true, allows asymmetric keys which do not match the specified algorithm. This option is intended only for backwards compatability and should be avoided.
// verify a token symmetric - synchronous
var decoded = jwt.verify(token, 'shhhhh');
console.log(decoded.foo) // bar

// verify a token symmetric
jwt.verify(token, 'shhhhh', function(err, decoded) {
  console.log(decoded.foo) // bar
});

// invalid token - synchronous
try {
  var decoded = jwt.verify(token, 'wrong-secret');
} catch(err) {
  // err
}

// invalid token
jwt.verify(token, 'wrong-secret', function(err, decoded) {
  // err
  // decoded undefined
});

// verify a token asymmetric
var cert = fs.readFileSync('public.pem');  // get public key
jwt.verify(token, cert, function(err, decoded) {
  console.log(decoded.foo) // bar
});

// verify audience
var cert = fs.readFileSync('public.pem');  // get public key
jwt.verify(token, cert, { audience: 'urn:foo' }, function(err, decoded) {
  // if audience mismatch, err == invalid audience
});

// verify issuer
var cert = fs.readFileSync('public.pem');  // get public key
jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer' }, function(err, decoded) {
  // if issuer mismatch, err == invalid issuer
});

// verify jwt id
var cert = fs.readFileSync('public.pem');  // get public key
jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid' }, function(err, decoded) {
  // if jwt id mismatch, err == invalid jwt id
});

// verify subject
var cert = fs.readFileSync('public.pem');  // get public key
jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid', subject: 'subject' }, function(err, decoded) {
  // if subject mismatch, err == invalid subject
});

// alg mismatch
var cert = fs.readFileSync('public.pem'); // get public key
jwt.verify(token, cert, { algorithms: ['RS256'] }, function (err, payload) {
  // if token alg != RS256,  err == invalid signature
});

// Verify using getKey callback
// Example uses https://github.com/auth0/node-jwks-rsa as a way to fetch the keys.
var jwksClient = require('jwks-rsa');
var client = jwksClient({
  jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json'
});
function getKey(header, callback){
  client.getSigningKey(header.kid, function(err, key) {
    var signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

jwt.verify(token, getKey, options, function(err, decoded) {
  console.log(decoded.foo) // bar
});
Need to peek into a JWT without verifying it? (Click to expand)

jwt.decode(token [, options])

(Synchronous) Returns the decoded payload without verifying if the signature is valid.

Warning: This will not verify whether the signature is valid. You should not use this for untrusted messages. You most likely want to use jwt.verify instead.

Warning: When the token comes from an untrusted source (e.g. user input or external request), the returned decoded payload should be treated like any other user input; please make sure to sanitize and only work with properties that are expected

token is the JsonWebToken string

options:

  • json: force JSON.parse on the payload even if the header doesn't contain "typ":"JWT".
  • complete: return an object with the decoded payload and header.

Example

// get the decoded payload ignoring signature, no secretOrPrivateKey needed
var decoded = jwt.decode(token);

// get the decoded payload and header
var decoded = jwt.decode(token, {complete: true});
console.log(decoded.header);
console.log(decoded.payload)

Errors & Codes

Possible thrown errors during verification. Error is the first argument of the verification callback.

TokenExpiredError

Thrown error if the token is expired.

Error object:

  • name: 'TokenExpiredError'
  • message: 'jwt expired'
  • expiredAt: [ExpDate]
jwt.verify(token, 'shhhhh', function(err, decoded) {
  if (err) {
    /*
      err = {
        name: 'TokenExpiredError',
        message: 'jwt expired',
        expiredAt: 1408621000
      }
    */
  }
});

JsonWebTokenError

Error object:

  • name: 'JsonWebTokenError'
  • message:
    • 'invalid token' - the header or payload could not be parsed
    • 'jwt malformed' - the token does not have three components (delimited by a .)
    • 'jwt signature is required'
    • 'invalid signature'
    • 'jwt audience invalid. expected: [OPTIONS AUDIENCE]'
    • 'jwt issuer invalid. expected: [OPTIONS ISSUER]'
    • 'jwt id invalid. expected: [OPTIONS JWT ID]'
    • 'jwt subject invalid. expected: [OPTIONS SUBJECT]'
jwt.verify(token, 'shhhhh', function(err, decoded) {
  if (err) {
    /*
      err = {
        name: 'JsonWebTokenError',
        message: 'jwt malformed'
      }
    */
  }
});

NotBeforeError

Thrown if current time is before the nbf claim.

Error object:

  • name: 'NotBeforeError'
  • message: 'jwt not active'
  • date: 2018-10-04T16:10:44.000Z
jwt.verify(token, 'shhhhh', function(err, decoded) {
  if (err) {
    /*
      err = {
        name: 'NotBeforeError',
        message: 'jwt not active',
        date: 2018-10-04T16:10:44.000Z
      }
    */
  }
});

Algorithms supported

Array of supported algorithms. The following algorithms are currently supported.

alg Parameter Value Digital Signature or MAC Algorithm
HS256 HMAC using SHA-256 hash algorithm
HS384 HMAC using SHA-384 hash algorithm
HS512 HMAC using SHA-512 hash algorithm
RS256 RSASSA-PKCS1-v1_5 using SHA-256 hash algorithm
RS384 RSASSA-PKCS1-v1_5 using SHA-384 hash algorithm
RS512 RSASSA-PKCS1-v1_5 using SHA-512 hash algorithm
PS256 RSASSA-PSS using SHA-256 hash algorithm (only node ^6.12.0 OR >=8.0.0)
PS384 RSASSA-PSS using SHA-384 hash algorithm (only node ^6.12.0 OR >=8.0.0)
PS512 RSASSA-PSS using SHA-512 hash algorithm (only node ^6.12.0 OR >=8.0.0)
ES256 ECDSA using P-256 curve and SHA-256 hash algorithm
ES384 ECDSA using P-384 curve and SHA-384 hash algorithm
ES512 ECDSA using P-521 curve and SHA-512 hash algorithm
none No digital signature or MAC value included

Refreshing JWTs

First of all, we recommend you to think carefully if auto-refreshing a JWT will not introduce any vulnerability in your system.

We are not comfortable including this as part of the library, however, you can take a look at this example to show how this could be accomplished. Apart from that example there are an issue and a pull request to get more knowledge about this topic.

TODO

  • X.509 certificate chain is not checked

Issue Reporting

If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues.

Author

Auth0

License

This project is licensed under the MIT license. See the LICENSE file for more info.

node-jsonwebtoken's People

Contributors

abalmos avatar agnoster avatar aldermoovel avatar awlayton avatar dominykas avatar dschenkelman avatar evolvah avatar fiddur avatar jackub avatar jacokoster avatar jacopofar avatar jakelacey2012 avatar jaredhanson avatar jfromaniello avatar joepie91 avatar junosuarez avatar luisfarzati avatar mitmaro avatar mprinc avatar nicokaiser avatar ntotten avatar panva avatar pose avatar risseraka avatar siacomuzzi avatar tatdk avatar tdantas avatar thebuscantswim avatar woloski avatar ziluvatar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-jsonwebtoken's Issues

.verify is synchronous, why does it need a callback?

Shouldn't there be an option to use .verify without the callback since it doesn't use any async code?

If you want, I could get a pull request up that allows for optional callback to the verify method? I understand that a callback can be preferred for error handling etc.

tl;dr; I can get a pull request up that allows sync use of .verify without breaking existing API. Should I?

Intermittent failures verifying using rs256 in browserify

This key fails to sign and verify using RS256 in browserify, but passes in node.js.

var NodeRSA = require('node-rsa');
var tape = require('tape');
var jwt = require('jsonwebtoken');

tape('test', function (t) {
  var details = {"publicKey":"-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKgmVzdsFz5lDE5Rme6qYcvcoExVlQTo\nBfnASFh1bpv4ych/A5r9Ip1q0eJDGv9JLVIecTxUPgHWUt1Ikr/TQGUCAwEAAQ==\n-----END PUBLIC KEY-----","privateKey":"-----BEGIN RSA PRIVATE KEY-----\nMIIBOgIBAAJBAKgmVzdsFz5lDE5Rme6qYcvcoExVlQToBfnASFh1bpv4ych/A5r9\nIp1q0eJDGv9JLVIecTxUPgHWUt1Ikr/TQGUCAwEAAQJAFvXtUOcUoXOA46zm3R0s\n73538RR6ncnlDv5/onyelvOADuwgCjJZ5ZR0Mhcb8sCR8XME8td/vNcDx3qJvHNH\nPQIhAOLYtPGD4qtjfFo2JnanbEW4899GdhMBjzc9qSqls7ybAiEAvcJ/+xTVEEX2\n/6b7iwfHQhve5PsIZzydtfhoiHwoRv8CIEntcdqbro1IWMhViWd13JVEV0XWgrhi\n87d/AtiBM/gtAiAMYAzcoQUsJIPxNECfVoiGJS8qG7z2jptybJrUm9Q8nQIhAI2X\n3TMJLjVmg/9WLFJGeD9MZIQ8oNwfN44r7wq85ttN\n-----END RSA PRIVATE KEY-----","pkf":"18:3e:57:98:fa:f3:c3:18:a8:61:9c:44:73:96:a2:f9:a2:1f:19:13"}

  var key = new NodeRSA(details.privateKey);

  t.same(key.exportKey('private'), details.privateKey);
  t.same(key.exportKey('public'), details.publicKey);

  var msg = {
    publicKey: details.publicKey,
    session: 'boop'
  };

  var message = jwt.sign(msg, details.privateKey, { algorithm: 'RS256'});

  var d = jwt.decode(message);
  var verified;

  try {
    verified = jwt.verify(message, d.publicKey, {algorithms: ['RS256']});
  } catch (e) {
    console.log(e);
    verified = false;
  }
  t.ok(verified, 'jwt is verified');
  t.end();
});

Error in Verify(): PEM_read_bio_PUBKEY

On OSX 10.10.2, Node v0.12.0 and jsonwebtoken v4.1.0

Using jsonwebtoken to create my own RS256-signed tokens in the ActionHero framework. Loaded the public key with api.auth.publicKey = fs.readFileSync(path.join(__dirname, '../', api.config.auth.publicKey));.

I am able encode, but not decode. When calling require('jsonwebtoken').verify(token,, api.auth.publicKey) I get a PEM_read_bio_PUBKEY failed error. Seems to be in the JWS library, judging from the stack trace.

Full error trace (in an ActionHero flavor):

2015-03-16 11:09:31 - error: ! uncaught error from action: action:status
2015-03-16 11:09:31 - error: ! connection details:
2015-03-16 11:09:31 - error: !     action: "status"
2015-03-16 11:09:31 - error: !     remoteIP: "127.0.0.1"
2015-03-16 11:09:31 - error: !     type: "web"
2015-03-16 11:09:31 - error: !     params: {"action":"status","apiVersion":1}
2015-03-16 11:09:31 - error: ! Error: PEM_read_bio_PUBKEY failed
2015-03-16 11:09:31 - error: !     at Error (native)
2015-03-16 11:09:31 - error: !     at Verify.verify (crypto.js:356:23)
2015-03-16 11:09:31 - error: !     at Object.verify (/project/Documents/Repositories/server/node_modules/jsonwebtoken/node_modules/jws/node_modules/jwa/index.js:65:21)
2015-03-16 11:09:31 - error: !     at Object.jwsVerify [as verify] (/project/Documents/Repositories/server/node_modules/jsonwebtoken/node_modules/jws/lib/verify-stream.js:68:15)
2015-03-16 11:09:31 - error: !     at Object.module.exports.verify (/project/Documents/Repositories/server/node_modules/jsonwebtoken/index.js:113:17)
2015-03-16 11:09:31 - error: !     at Object.api.auth.isAuthenticated (/project/Documents/Repositories/server/initializers/1500_auth.js:38:18)
2015-03-16 11:09:31 - error: !     at /project/Documents/Repositories/server/initializers/1500_auth.js:50:22
2015-03-16 11:09:31 - error: !     at /project/Documents/Repositories/server/node_modules/actionhero/initializers/actionProcessor.js:135:15
2015-03-16 11:09:31 - error: !     at /project/Documents/Repositories/server/node_modules/actionhero/node_modules/async/lib/async.js:610:21
2015-03-16 11:09:31 - error: !     at /project/Documents/Repositories/server/node_modules/actionhero/node_modules/async

Issuer and Audience are verified only if provided

These lines of code are the cause:

  if (payload.aud && options.audience) {
    if (payload.aud !== options.audience)
      return callback(new Error('jwt audience invalid. expected: ' + payload.aud));
  }

  if (payload.iss && options.issuer) {
    if (payload.iss !== options.issuer)
      return callback(new Error('jwt issuer invalid. expected: ' + payload.iss));
  }

Repro tests:

  describe('when signing a token without issuer', function() {
    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });

    it('should check issuer', function() {
      jwt.verify(token, pub, { issuer: 'urn:foo' }, function(err, decoded) {
        assert.isUndefined(decoded);
        assert.isNotNull(err);
      });
    });
  });

  describe('when signing a token without audience', function() {
    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });

    it('should check audience', function(done) {
      jwt.verify(token, pub, { audience: 'urn:wrong' }, function(err, decoded) {
        assert.isUndefined(decoded);
        assert.isNotNull(err);
        done();
      });
    });

  });

SyntaxError when payload is a string

[sailor-0 (err)] at Object.parse (native)
[sailor-0 (err)] at Object.jwsDecode as decode
[sailor-0 (err)] at Object.module.exports.decode (/Users/josefranciscoverdugambin/Downloads/appToken/node_modules/jsonwebtoken/index.js:4:21)
[sailor-0 (err)] at Object.module.exports.verify (/Users/josefranciscoverdugambin/Downloads/appToken/node_modules/jsonwebtoken/index.js:56:22)

Charset encoding

Hi there, I'm currently using JWT for encoding some basic session data to be persisted over auths, within that data there goes a user.name into the token. Everything works wonderfully, i mean it, like really thank you and all that. But I noticed when encoding my own name over QA phases that utf8 chars get encoded in a weird way.

screen shot 2014-12-21 at 4 01 09

You can reproduce it with latin accented letters encoded over jwt data. Try áéíóú.

I can handle it on client-side decoding utf8 data, but I think that is not the expected library behavior. Please let me know if i'm doing someting wrong or is this a real issue.

Again, thank you auth0 :)
Happy coding.

Exception thrown when used with node v0.10.32 whereas working fine with node v0.10.18

This is how i am using it:
var token = require("jsonwebtoken").sign({name:"some name",email:"some email"}, 'hello-private-key', { algorithm: 'RS256'});

Same implementation is working in v0.10.18 whereas in my other machine where i am running v0.10.32, it is not working.

Below is the stack trace:
140735299650320:error:0906D06C:PEM routines:PEM_read_bio:no start line:../deps/openssl/openssl/crypto/pem/pem_lib.c:703:Expecting: ANY PRIVATE KEY

/Users/narendra/Documents/workspace/NodeJsWorkspace/mean-jwt-auth/node_modules/mongoose/node_modules/mpromise/lib/promise.js:108
if (this.ended && !this.hasRejectListeners()) throw reason;
^
Error: SignFinal error
at Sign.sign (crypto.js:398:27)
at Object.sign (/Users/narendra/Documents/workspace/NodeJsWorkspace/mean-jwt-auth/node_modules/jsonwebtoken/node_modules/jws/node_modules/jwa/index.js:52:47)
at Object.jwsSign as sign
at Object.module.exports.sign (/Users/narendra/Documents/workspace/NodeJsWorkspace/mean-jwt-auth/node_modules/jsonwebtoken/index.js:46:20)

Improve expirationInMinutes precision

Currently this library only allows the token to be signed with a expiration in minutes. Shoudn't it be able to handle in a more granular way — maybe using a Date object?

At this moment, it's possible to use float values (e.g. 1.5 minutes) but I'm not sure if the current output ("exp": 1422230816.994) is valid based on JWT specs. If not, maybe a simple rounding would probably suffice too.

How to check more than one Issuer ?

I want to check if issuer1 or issuer2 is issued then its Valid

jwt.verify(token, jwtSecret, { audience: 'urn:foo', issuer: 'urn:issuer1' }, function(err, decoded) {
  if(err){

   }
});

and is there iat (issued at) option ?

Problems with utf8 payload

hello im sending an utf8 payload for example containing the letter ébut when angular decodes it i get é why is that? just with the token all the other responses done directly from nodejs i get the correct chars

Audience in token should support arrays

Per the spec:

   In the general case, the "aud" value is an array of case-
   sensitive strings, each containing a StringOrURI value.  In the
   special case when the JWT has one audience, the "aud" value MAY be a
   single case-sensitive string containing a StringOrURI value.

TypeError: Cannot read property 'payload' of null

Looking for some help here - I have a simple Node/Express app which is validating a token:

exports.validate = function(req, res) {
jwt.verify(req.body.token, token_secret, function (err, decoded) {
if (err) {
res.json({user: null})
} else {
if (token_is_valid(req.body.token)) {
res.json({user: decoded});
} else {
res.json({user: null});
}
}
});
}

When called via a POST with a body of { token: 'a previously generated jwt'} I get:
TypeError: Cannot read property 'payload' of null
at Object.module.exports.decode (/Users/peterwhitfield/projects/lawpath/V2/microservices/sessions/node_modules/jsonwebtoken/index.js:4:25)
at Object.module.exports.verify (/Users/peterwhitfield/projects/lawpath/V2/microservices/sessions/node_modules/jsonwebtoken/index.js:55:22)
at Object.exports.validate as handle
at next_layer (/Users/peterwhitfield/projects/lawpath/V2/microservices/sessions/node_modules/express/lib/router/route.js:103:13)
at Route.dispatch (/Users/peterwhitfield/projects/lawpath/V2/microservices/sessions/node_modules/express/lib/router/route.js:107:5)
at c (/Users/peterwhitfield/projects/lawpath/V2/microservices/sessions/node_modules/express/lib/router/index.js:195:24)
at Function.proto.process_params (/Users/peterwhitfield/projects/lawpath/V2/microservices/sessions/node_modules/express/lib/router/index.js:251:12)
at next (/Users/peterwhitfield/projects/lawpath/V2/microservices/sessions/node_modules/express/lib/router/index.js:189:19)
at next (/Users/peterwhitfield/projects/lawpath/V2/microservices/sessions/node_modules/express/lib/router/index.js:166:38)
at Function.proto.handle (/Users/peterwhitfield/projects/lawpath/V2/microservices/sessions/node_modules/express/lib/router/index.js:234:5)

I have checked that req.body.token actually contains the token. If I take the same token value and insert it directly into the verify call, it works properly.

I hope you can shed some light on this.

Can't create npm shrinkwrap with express-jwt in package.json

I have a project where I use both node-jsonwebtoken and express-jwt. After the upgrade to node-jsonwebtoken 5.0.0, I can't create a npm shrinkwrap, as express-jwt, I believe, depends on 4.x. Here's the npm debug log.

0 info it worked if it ends with ok
1 verbose cli [ 'node', '/usr/local/bin/npm', 'shrinkwrap' ]
2 info using [email protected]
3 info using [email protected]
4 verbose node symlink /usr/local/bin/node
5 warn unmet dependency /Users/gp/Projects/myproject/node_modules/express-jwt requires jsonwebtoken@'~4.2.0' but will load
5 warn unmet dependency /Users/gp/Projects/myproject/node_modules/jsonwebtoken,
5 warn unmet dependency which is version 5.0.0
6 verbose stack Error: Problems were encountered
6 verbose stack Please correct and try again.
6 verbose stack invalid: [email protected] /Users/gp/Projects/myproject/node_modules/jsonwebtoken
6 verbose stack     at shrinkwrap_ (/usr/local/lib/node_modules/npm/lib/shrinkwrap.js:37:15)
6 verbose stack     at /usr/local/lib/node_modules/npm/lib/shrinkwrap.js:31:5
6 verbose stack     at /usr/local/lib/node_modules/npm/lib/ls.js:47:30
6 verbose stack     at /usr/local/lib/node_modules/npm/node_modules/read-installed/read-installed.js:138:5
6 verbose stack     at /usr/local/lib/node_modules/npm/node_modules/read-installed/read-installed.js:251:14
6 verbose stack     at cb (/usr/local/lib/node_modules/npm/node_modules/slide/lib/async-map.js:47:24)
6 verbose stack     at /usr/local/lib/node_modules/npm/node_modules/read-installed/read-installed.js:251:14
6 verbose stack     at cb (/usr/local/lib/node_modules/npm/node_modules/slide/lib/async-map.js:47:24)
6 verbose stack     at /usr/local/lib/node_modules/npm/node_modules/read-installed/read-installed.js:251:14
6 verbose stack     at cb (/usr/local/lib/node_modules/npm/node_modules/slide/lib/async-map.js:47:24)
7 verbose cwd /Users/gp/Projects/myproject
8 error Darwin 14.3.0
9 error argv "node" "/usr/local/bin/npm" "shrinkwrap"
10 error node v0.12.2
11 error npm  v2.7.6
12 error Problems were encountered
12 error Please correct and try again.
12 error invalid: [email protected] /Users/gp/Projects/myproject/node_modules/jsonwebtoken
13 error If you need help, you may report this error at:
13 error     <https://github.com/npm/npm/issues>
14 verbose exit [ 1, true ]

Tokens don't expire

Hi,
I am creating the token like so:
var token = jwt.sign(user, secret, {expiresInMinutes: 1});
and verifying using:

jwt.verify(token, secret, function(err, decoded) { if (err) { console.log(err); } else { console.log(decoded); }
But, I don't see any errors after one minute and the token is successfully decoded every time. Am I doing anything wrong?

My jsonwebtoken version is 1.3.0, if that helps.

Exception when using RS256 with certificate

Hi

Im using https://github.com/substack/rsa-json to create public and private pem encoded keys.

However when i try to use them to encode a jwt using RS256 this error is thrown:

Error: error:0906D06C:PEM routines:PEM_read_bio:no start line\ at Error (native)\ at Sign.sign (crypto.js:327:26)\ at Object.sign
(/Project/node_modules/jsonwebtoken/node_modules/jws/node_modules/jwa/index.js:52:47)\ at Object.jwsSign [as sign
(/Project/node_modules/jsonwebtoken/node_modules/jws/index.js:34:26)\ at Object.module.exports.sign
(/Project/node_modules/jsonwebtoken/index.js:46:20)\ at generateToken
(/Project/app/services/auth/loginservice.js:105:21)\ at _fulfilled
(/Project/node_modules/q/q.js:794:54)\ at self.promiseDispatch.done
(/Project/node_modules/q/q.js:823:30)\ at Promise.promise.promiseDispatch
(/Project/node_modules/q/q.js:756:13)\ at
/Project/node_modules/q/q.js:516:49

Since the documentation says it needs a buffer i tried to wrap the string in a buffer but that made no difference.

Do i need to load the keys from a file? Is there no other way?

An exception is thrown when payload is a string

When using jwt.verify or jwt.decode with a payload that was created from a string, there is an exception.

var jwt = require('jsonwebtoken');
var token = jwt.sign('hello', '123');
jwt.verify(token, '123', function(err, decoded) {
    // Will never run because of 'SyntaxError: Unexpected token'
    console.log(decoded);
});

According to the docs for sign() - "payload could be an literal, buffer or string".

Signing, object vs string

If payload is not a buffer or a string, it will be coerced into a string using JSON.stringify.

Shouldn't these result in the same output or am I missing something?

jwt.sign({x: 1}, "secret")
// 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ4IjoxLCJpYXQiOjE0MjE4NjE1ODB9.YBvFd7_yRFKGRs09T1I6ChZze-6OmY7SpiCXxVzknVc'

jwt.sign(JSON.stringify({x: 1}), "secret")
// 'eyJhbGciOiJIUzI1NiJ9.eyJ4IjoxfQ.XOAA7XIKOu4yBszS83Yc_js4QvGVrdubYLQdNnpQ8J4'

Audience, issuer, expiration, etc are lost when using a string as payload.

When using a string as payload, the issuer, expiration, audience and subject are lost. It is not possible to attach properties to a primitive and also they do not get serialized anyway, as it get serialized as a string. A possible solution is to put the string in a object literal and attach this data to the literal too.

At the moment, using a string as payload also causes a parsing exception when decoding it due to a problem in the node-jws library.

Options ignored when payload isn't an object

According to the docs, the payload can be a string, buffer, or object. However, the sign function blindly tries to add the exp, iss, aud, and sub properties to the payload, so when it's a primitive those properties get lost.

I'm submitting a pull request for a possible fix, although there might be a need for better type checking/handling.

Prevention against replay attacks

Hello,

So this is the workflow I have at this moment for using JWT:

  • User logs in, sends usr/pwd.
  • Node validates it against an old .NET DB, if the usr/pwd matches, I issue a JWT with 5min expiration and send it back to client.
  • I store the token using mozilla's localforage.
  • Everytime I do a new request, I invalidate the current token (adding it to a blacklist), and add issue a new token in response.

So far so good, everything works like a charm, but I have a reaaaaally big concern... what happens if someone grabs that token that I have saved on localstorage? and then creates the same request trhu, let's say, POSTMAN? That's going to:

  • Invalidate my token and kick me out of the session where I'm using the current token (already blacklisted because it was used by the evil genious with POSTMAN)
  • Return new tokens to evil genious.

So how possible is that someone is able to hack my localstorage/indexedDB/WebSQL?
Are my steps wrong?
What's the right way to implement a "nonce"? (I think I don't need this since I'm doing like a heartbeat, everytime I do a request with my token, I return a new one and the previous one gets blacklisted)

Thanks in advance

Consider changelog

Please consider the implementation of a changelog.

I spent 30 minutes trying to figure out what was the breaking change in the v4.0.0 release. At least major releases should be well documented.

iat field calculation at sign method

Hello!

At sign method I see line
payload.iat = Math.round(Date.now() / 1000);

If Date.now() / 1000 returns 1407247380.576 we get token that will become valid after 1 second from the time it was exactly issued. I think it's better to use Math.floor instead of Math.round.

Thank you!

encrypting payload

I expected when using a privatekey it will encrypt the payload too!
I think I misunderstood with some usage of algorithms available for jwt.
why we should use encryption and its performance drop in comparison to hashing ?

as a feature I think it could be useful to encrypt the payload , I expect the pros of encryption is when we encrypt the payload.

error in jwt.verify

Hi there,

I'm working with jwt.verify and I'm getting an "invalid algorithm" error.

Uncaught JsonWebTokenError {name: "JsonWebTokenError", message: "invalid algorithm"}

Note: I tried switching up my PEM encoding from PKCS8 to traditional OpenSSL, but then I get an "invalid signature" error instead, which leads me to believe that PKCS8 is required.

Here is my code:

var jwt = require('jsonwebtoken');
var payload = {foo: 'bar'};
var rsa_token = jwt.sign(payload, private_pem, {algorithms: 'RS256'});
jwt.verify(rsa_token, public_pem);

Is RS256 properly supported?

Also please note that I'm testing this in the browser with browserify.

Any guidance on this would be much appreciated. Thanks!

Error Audience check

Always got this error

{ name: 'JsonWebTokenError',
message: 'jwt audience invalid. expected: undefined' }

I've correctly specified

jwt.verify(token,secred,{audience : 'https://asksja.com'},function(err,decoded) {

      if(err){
        console.log(err);
        return res.status(401).json({status:401,msg:"Invalid audience"});        
      }

      console.log("Audience Pass");
      next();

    });

You should try check your index.js line 103
console.log(payload);

the output still

{ audience: ff
issuer:ff
subject: fff
email: ggg
iat: 1423041815 }

and you check below it like

payload.aud , this would be 'undefine'

Also , I have this token generated from iOS library

 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJlbWFpbCI6Im5hZHlhQHlhaG9vLmNvbSIsImF1ZGllbmNlIjoiaHR0cHM6XC9cL2FwaS50dWluZ2xlLmNvbSIsInN1YmplY3QiOiI1MTM3ODI5MjIxNDg3NDg0ODI0NDAxIiwiaXNzdWVyIjoibXlQYWNrYWdlLnR1aW5nbGUuY29tIiwiaWF0IjoxNDIwOTYwOTI0fQ==.55G6LfE9Zkse0Z7bppTK9IhhTe8DMSq0XlJrtajk4DhOSsHVBXDtwuXEeLc7t0Sv5BosV5f2NDePrSjjapBfkA== 

its valid when check it on jwt.io

but invalid signature when verify

Thanks

@jfromaniello

Accessing payload even without verifying

It is some times useful to be able to access the payload even though the verification fails. On PyJWT we do it like this:

jwt.decode("someJWTstring", verify=False)

I could always directly use jws to decode the jwtString first and the do verification. What do you guys think about this?

Error on insufficient key length

Might I suggest we throw an error when the user tries to sign a token with a key of a length with an insufficient length?

I believe a length > 8 should be sufficient against brute-force attacks.

Let me know what you guys think.

Can't install jsonwebtoken due to 3rd party issue

I receive the following error message when attempting to install jsonwebtoken, npm-version: 1.1.65.

npm http 304 https://registry.npmjs.org/buffer-equal-constant-time
npm ERR! Error: No compatible version found: buffer-equal-constant-time@'^1.0.1'
npm ERR! Valid install targets:
npm ERR! ["1.0.0","1.0.1"]
npm ERR! at installTargetsError (/usr/local/lib/node_modules/npm/lib/cache.js:563:10)
npm ERR! at /usr/local/lib/node_modules/npm/lib/cache.js:478:10
npm ERR! at saved (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/get.js:138:7)
npm ERR! at /usr/local/lib/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:218:7
npm ERR! at Object.oncomplete (fs.js:297:15)
npm ERR! If you need help, you may report this log at:
npm ERR! http://github.com/isaacs/npm/issues
npm ERR! or email it to:
npm ERR! [email protected]

Add license to project

Hello Matias,

Even though the license is included in the README.md file, it would better to also include it in its own file. This way license crawlers will be able to easily access it.

Saludos,

-- Tito

[security] Update node-jws to 3.0.0

node-jws is now at version 3.0.0. due to a security fix. The change log for 3.0.0 is here.

BREAKING: jwt.verify now requires an algorithm parameter, and
jws.createVerify requires an algorithm option. The "alg" field
signature headers is ignored. This mitigates a critical security flaw
in the library which would allow an attacker to generate signatures with
arbitrary contents that would be accepted by jwt.verify. See
https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
for details.

update jws?

at this moment the lastest version of jws is 2.x... time to update?

Sign token, generate different token

Hi there, I am using this module with a express.js application and also using express-jwt.

Well, in the login process each time a post to the /login url a new token is generated and saved to redis. I have a validation that if a token exists it wont be set to redis. but each time a token is signed/generated it is different even when I use the same secret string and the same payload.

The code is

var data = { _id: user.id, username: user.nickname, email: user.email, token: jsonwebtoken.sign({ _id: user.id }, 'secret', { expiresInMinutes: TOKEN_EXPIRATION }) };

But the data.token each post to /login route is different and it's set to redis.

Can you help me?

Regards!

Sign method should return object instead of string

It would be nice if the sign method actually returned an object with the token string as a property and the expire date time and other values. I need to add it to a database so I can verify it is a valid token so I now end up having to verify the token right after signing it so I can load them into a database.

I know this is a requirement but it is for our security to still verify the key when it comes back. I hope to eventually take this out once JWT is more solid and excepted. Any help on convincing management on this would be great as well.

Update node-jws dependency

Hi!

We made some fix with node-jws and released a new mayor version.

It's fix browsers window.atob compatibility when claims contains latin1 characters.

Would be nice if you update node-jws dependency to ~1.0.0

Thanks!

Text input does not work in iOS

There are a few issues I found:

  1. When clicking on the textbox and holding the delete key only one character is deleted and the delete key is released. The expected iOS behavior is that you can click and hold to continually delete.
  2. You cannot click and hold to select the text thus making it difficult to clear the textbook.
  3. You cannot click and hold to copy or paste. Paste is most problematic because it makes the site impossible to use on iOS unless you memorize and type the key manually.

Here is a video of the interactions. At then end you will see me trying to click, click and hold, etc.

https://www.dropbox.com/s/26bw8lkp380k8lv/2015-02-06_12-24-24.mp4?dl=0

My guess is we are just intercepting too many events incorrectly. One nice thing would be on mobile browsers that once you click on the text box it automatically clears then the user can easily paste in the box.

RS256 problem 4.2.x

Hi,

this package have a problem with decoding RS256 signed messages

var jwt = require('jsonwebtoken');
var fs = require('fs');
var cert_pub = fs.readFileSync('app.rsa.pub');
var cert_priv = fs.readFileSync('app.rsa');

var token = jwt.sign({ foo: 'bar' }, cert_priv, { algorithm: 'RS256'});
jwt.verify(token, cert_pub, function(err, decoded) {
console.log("Decoded: " + JSON.stringify(decoded));
console.log("Error: " + err);
});

This code woks fine in 4.1.0, but on 4.2.0 version problem is with verifying token.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.