Giter Site home page Giter Site logo

node-jws's Introduction

node-jws Build Status

An implementation of JSON Web Signatures.

This was developed against draft-ietf-jose-json-web-signature-08 and implements the entire spec except X.509 Certificate Chain signing/verifying (patches welcome).

There are both synchronous (jws.sign, jws.verify) and streaming (jws.createSign, jws.createVerify) APIs.

Install

$ npm install jws

Usage

jws.ALGORITHMS

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 using SHA-256 hash algorithm
RS384 RSASSA using SHA-384 hash algorithm
RS512 RSASSA using SHA-512 hash algorithm
PS256 RSASSA-PSS using SHA-256 hash algorithm
PS384 RSASSA-PSS using SHA-384 hash algorithm
PS512 RSASSA-PSS using SHA-512 hash algorithm
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

jws.sign(options)

(Synchronous) Return a JSON Web Signature for a header and a payload.

Options:

  • header
  • payload
  • secret or privateKey
  • encoding (Optional, defaults to 'utf8')

header must be an object with an alg property. header.alg must be one a value found in jws.ALGORITHMS. See above for a table of supported algorithms.

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

Example

const signature = jws.sign({
  header: { alg: 'HS256' },
  payload: 'h. jon benjamin',
  secret: 'has a van',
});

jws.verify(signature, algorithm, secretOrKey)

(Synchronous) Returns true or false for whether a signature matches a secret or key.

signature is a JWS Signature. header.alg must be a value found in jws.ALGORITHMS. See above for a table of supported algorithms. secretOrKey is a string or buffer containing either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA.

Note that the "alg" value from the signature header is ignored.

jws.decode(signature)

(Synchronous) Returns the decoded header, decoded payload, and signature parts of the JWS Signature.

Returns an object with three properties, e.g.

{ header: { alg: 'HS256' },
  payload: 'h. jon benjamin',
  signature: 'YOWPewyGHKu4Y_0M_vtlEnNlqmFOclqp4Hy6hVHfFT4'
}

jws.createSign(options)

Returns a new SignStream object.

Options:

  • header (required)
  • payload
  • key || privateKey || secret
  • encoding (Optional, defaults to 'utf8')

Other than header, all options expect a string or a buffer when the value is known ahead of time, or a stream for convenience. key/privateKey/secret may also be an object when using an encrypted private key, see the crypto documentation.

Example:

// This...
jws.createSign({
  header: { alg: 'RS256' },
  privateKey: privateKeyStream,
  payload: payloadStream,
}).on('done', function(signature) {
  // ...
});

// is equivalent to this:
const signer = jws.createSign({
  header: { alg: 'RS256' },
});
privateKeyStream.pipe(signer.privateKey);
payloadStream.pipe(signer.payload);
signer.on('done', function(signature) {
  // ...
});

jws.createVerify(options)

Returns a new VerifyStream object.

Options:

  • signature
  • algorithm
  • key || publicKey || secret
  • encoding (Optional, defaults to 'utf8')

All options expect a string or a buffer when the value is known ahead of time, or a stream for convenience.

Example:

// This...
jws.createVerify({
  publicKey: pubKeyStream,
  signature: sigStream,
}).on('done', function(verified, obj) {
  // ...
});

// is equivilant to this:
const verifier = jws.createVerify();
pubKeyStream.pipe(verifier.publicKey);
sigStream.pipe(verifier.signature);
verifier.on('done', function(verified, obj) {
  // ...
});

Class: SignStream

A Readable Stream that emits a single data event (the calculated signature) when done.

Event: 'done'

function (signature) { }

signer.payload

A Writable Stream that expects the JWS payload. Do not use if you passed a payload option to the constructor.

Example:

payloadStream.pipe(signer.payload);

signer.secret
signer.key
signer.privateKey

A Writable Stream. Expects the JWS secret for HMAC, or the privateKey for ECDSA and RSA. Do not use if you passed a secret or key option to the constructor.

Example:

privateKeyStream.pipe(signer.privateKey);

Class: VerifyStream

This is a Readable Stream that emits a single data event, the result of whether or not that signature was valid.

Event: 'done'

function (valid, obj) { }

valid is a boolean for whether or not the signature is valid.

verifier.signature

A Writable Stream that expects a JWS Signature. Do not use if you passed a signature option to the constructor.

verifier.secret
verifier.key
verifier.publicKey

A Writable Stream that expects a public key or secret. Do not use if you passed a key or secret option to the constructor.

TODO

  • It feels like there should be some convenience options/APIs for defining the algorithm rather than having to define a header object with { alg: 'ES512' } or whatever every time.

  • X.509 support, ugh

License

MIT

Copyright (c) 2013-2015 Brian J. Brennan

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

node-jws's People

Contributors

andygout avatar brianloveswords avatar calinou avatar fearphage avatar forivall avatar frantello avatar graingert avatar marco-c avatar markherhold avatar olleolleolle avatar omsmith avatar ralphtheninja avatar shane-tomlinson avatar simonexmachina avatar sre-57-opslevel[bot] avatar tanepiper 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

node-jws's Issues

base64 encoded tokens (with padding) rejected

I have tokens that appear to have been generated using base64 encoding instead of base64url encoding (3rd party auth system) and line 8 of verify-stream.js defines the pattern which the token must match. That doesn't currently include '=' padding, which is causing these tokens to be rejected as invalid.

I'm reading through the spec, and while it's pretty clear that token issuers should not include padding, it also appears to recommend that validation should allow for padding.

Thoughts?

x5c support

I have a couple JWTs that use x5c in the headers (Android SafetyNet attestation, FIDO Metadata Service). Would it be possible to add validation of JWS that's using x5c?

Here's the Android SafetyNet JWS:

eyJhbGciOiJSUzI1NiIsIng1YyI6WyJNSUlFaWpDQ0EzS2dBd0lCQWdJSVlrWW81RjBnODZrd0RRWUpLb1pJaHZjTkFRRUxCUUF3VkRFTE1Ba0dBMVVFQmhNQ1ZWTXhIakFjQmdOVkJBb1RGVWR2YjJkc1pTQlVjblZ6ZENCVFpYSjJhV05sY3pFbE1DTUdBMVVFQXhNY1IyOXZaMnhsSUVsdWRHVnlibVYwSUVGMWRHaHZjbWwwZVNCSE16QWVGdzB4TnpFeU1EUXhNekU0TkROYUZ3MHhPREV5TURNd01EQXdNREJhTUd3eEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUlEQXBEWVd4cFptOXlibWxoTVJZd0ZBWURWUVFIREExTmIzVnVkR0ZwYmlCV2FXVjNNUk13RVFZRFZRUUtEQXBIYjI5bmJHVWdTVzVqTVJzd0dRWURWUVFEREJKaGRIUmxjM1F1WVc1a2NtOXBaQzVqYjIwd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUNVajh3WW9QaXhLYmJWOHNnWWd2TVRmWCtkSXNGVE9rZ0tPbGhUMGkwYmNERlpLMnJPeEpaMnVTTFNWaFl2aXBaTkUzSEpRWXV1WXdGaml5K3lrZmF0QUdTalJ6RjFiMzF1NDMvN29HNWpNaDNTMzdhbHdqVWI4Q1dpVHhvaXBWT1l3S0t6dVV5a3FFQ3RqbGhKNEFrV2FEUytaeEtFcU9hZTl0bkNnZUhsbFpFL09SZ2VNYXgyWE5Db0g2c3JURVJja3NqelpackFXeEtzZGZ2VnJYTnpDUjlEeFZBU3VJNkx6d2g4RFNsMkVPb2tic2FuWisrL0pxTWVBQkZmUHdqeXdyYjBwckVVeTBwYWVWc3VkKzBwZWV4Sy81K0U2a3BZR0s0WksybmtvVkx1Z0U1dGFIckFqODNRK1BPYmJ2T3pXY0ZrcG5WS3lqbzZLUUFtWDZXSkFnTUJBQUdqZ2dGR01JSUJRakFUQmdOVkhTVUVEREFLQmdnckJnRUZCUWNEQVRBZEJnTlZIUkVFRmpBVWdoSmhkSFJsYzNRdVlXNWtjbTlwWkM1amIyMHdhQVlJS3dZQkJRVUhBUUVFWERCYU1DMEdDQ3NHQVFVRkJ6QUNoaUZvZEhSd09pOHZjR3RwTG1kdmIyY3ZaM055TWk5SFZGTkhTVUZITXk1amNuUXdLUVlJS3dZQkJRVUhNQUdHSFdoMGRIQTZMeTl2WTNOd0xuQnJhUzVuYjI5bkwwZFVVMGRKUVVjek1CMEdBMVVkRGdRV0JCUUc4SXJRdEZSNkNVU2tpa2IzYWltc20yNmNCVEFNQmdOVkhSTUJBZjhFQWpBQU1COEdBMVVkSXdRWU1CYUFGSGZDdUZDYVozWjJzUzNDaHRDRG9INm1mcnBMTUNFR0ExVWRJQVFhTUJnd0RBWUtLd1lCQkFIV2VRSUZBekFJQmdabmdRd0JBZ0l3TVFZRFZSMGZCQ293S0RBbW9DU2dJb1lnYUhSMGNEb3ZMMk55YkM1d2Eya3VaMjl2Wnk5SFZGTkhTVUZITXk1amNtd3dEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRi9Sek5uQzVEekJVQnRuaDJudEpMV0VRaDl6RWVGWmZQTDlRb2tybEFvWGdqV2dOOHBTUlUxbFZHSXB0ek14R2h5My9PUlJaVGE2RDJEeThodkNEckZJMytsQ1kwMU1MNVE2WE5FNVJzMmQxUmlacE1zekQ0S1FaTkczaFowQkZOUS9janJDbUxCT0dLa0VVMWRtQVhzRkpYSmlPcjJDTlRCT1R1OUViTFdoUWZkQ0YxYnd6eXUrVzZiUVN2OFFEbjVPZE1TL1BxRTFkRWdldC82RUlSQjc2MUtmWlErL0RFNkxwM1RyWlRwT0ZERGdYaCtMZ0dPc3doRWxqOWMzdlpIR0puaGpwdDhya2Jpci8ydUxHZnhsVlo0SzF4NURSTjBQVUxkOXlQU21qZythajErdEh3STFtUW1aVlk3cXZPNURnaE94aEpNR2x6NmxMaVptem9nPSIsIk1JSUVYRENDQTBTZ0F3SUJBZ0lOQWVPcE1CejhjZ1k0UDVwVEhUQU5CZ2txaGtpRzl3MEJBUXNGQURCTU1TQXdIZ1lEVlFRTEV4ZEhiRzlpWVd4VGFXZHVJRkp2YjNRZ1EwRWdMU0JTTWpFVE1CRUdBMVVFQ2hNS1IyeHZZbUZzVTJsbmJqRVRNQkVHQTFVRUF4TUtSMnh2WW1Gc1UybG5iakFlRncweE56QTJNVFV3TURBd05ESmFGdzB5TVRFeU1UVXdNREF3TkRKYU1GUXhDekFKQmdOVkJBWVRBbFZUTVI0d0hBWURWUVFLRXhWSGIyOW5iR1VnVkhKMWMzUWdVMlZ5ZG1salpYTXhKVEFqQmdOVkJBTVRIRWR2YjJkc1pTQkpiblJsY201bGRDQkJkWFJvYjNKcGRIa2dSek13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRREtVa3ZxSHYvT0pHdW8ybklZYU5WV1hRNUlXaTAxQ1haYXo2VElITEdwL2xPSis2MDAvNGhibjd2bjZBQUIzRFZ6ZFFPdHM3RzVwSDBySm5uT0ZVQUs3MUc0bnpLTWZIQ0dVa3NXL21vbmErWTJlbUpRMk4rYWljd0pLZXRQS1JTSWdBdVBPQjZBYWhoOEhiMlhPM2g5UlVrMlQwSE5vdUIyVnp4b01YbGt5VzdYVVI1bXc2SmtMSG5BNTJYRFZvUlRXa050eTVvQ0lOTHZHbW5Sc0oxem91QXFZR1ZRTWMvN3N5Ky9FWWhBTHJWSkVBOEtidHlYK3I4c253VTVDMWhVcndhVzZNV09BUmE4cUJwTlFjV1RrYUllb1l2eS9zR0lKRW1qUjB2RkV3SGRwMWNTYVdJcjYvNGc3Mm43T3FYd2ZpbnU3WllXOTdFZm9PU1FKZUF6QWdNQkFBR2pnZ0V6TUlJQkx6QU9CZ05WSFE4QkFmOEVCQU1DQVlZd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUdDQ3NHQVFVRkJ3TUNNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3SFFZRFZSME9CQllFRkhmQ3VGQ2FaM1oyc1MzQ2h0Q0RvSDZtZnJwTE1COEdBMVVkSXdRWU1CYUFGSnZpQjFkbkhCN0FhZ2JlV2JTYUxkL2NHWVl1TURVR0NDc0dBUVVGQndFQkJDa3dKekFsQmdnckJnRUZCUWN3QVlZWmFIUjBjRG92TDI5amMzQXVjR3RwTG1kdmIyY3ZaM055TWpBeUJnTlZIUjhFS3pBcE1DZWdKYUFqaGlGb2RIUndPaTh2WTNKc0xuQnJhUzVuYjI5bkwyZHpjakl2WjNOeU1pNWpjbXd3UHdZRFZSMGdCRGd3TmpBMEJnWm5nUXdCQWdJd0tqQW9CZ2dyQmdFRkJRY0NBUlljYUhSMGNITTZMeTl3YTJrdVoyOXZaeTl5WlhCdmMybDBiM0o1THpBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQUhMZUpsdVJUN2J2czI2Z3lBWjhzbzgxdHJVSVNkN080NXNrRFVtQWdlMWNueGhHMVAyY05tU3hiV3NvaUN0MmV1eDlMU0QrUEFqMkxJWVJGSFczMS82eG9pYzFrNHRiV1hrRENqaXIzN3hUVE5xUkFNUFV5RlJXU2R2dCtubFBxd25iOE9hMkkvbWFTSnVrY3hEak5TZnBEaC9CZDFsWk5nZGQvOGNMZHNFMyt3eXB1Zko5dVhPMWlRcG5oOXpidUZJd3NJT05HbDFwM0E4Q2d4a3FJL1VBaWgzSmFHT3FjcGNkYUNJemtCYVI5dVlRMVg0azJWZzVBUFJMb3V6Vnk3YThJVms2d3V5NnBtK1Q3SFQ0TFk4aWJTNUZFWmxmQUZMU1c4TndzVno5U0JLMlZxbjFOMFBJTW41eEE2TlpWYzdvODM1RExBRnNoRVdmQzdUSWUzZz09Il19.eyJub25jZSI6ImxXa0lqeDdPNHlNcFZBTmR2UkRYeXVPUk1Gb25VYlZadTQvWHk3SXB2ZFJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFLZ2x4SHlmblJLQVpWcWlKZElxdHFmNEk5ZHgwb082L3pBTzhUbkRvanZFWkFxMkRaa0J5STFmY29XVlFFcS9PM0ZMSDVhT3d6YnJyeHJKNjVVNWRZcWxBUUlESmlBQklWZ2doNU9KZllSRHpWR0lvd0txVTU3QW5vVmpqZG1takdpOXpsTWtqQVZWOURBaVdDRHIwaVNpMHZpSUtOUE1USWROMjhnV05ta2N3T3I2RFF4NjZNUGZmM09kbSt1NmVKcUxCbDFIMlMydHJBQkhMaW5rbnN5Vk1QbS9CTlVWWjJKRmxyODAiLCJ0aW1lc3RhbXBNcyI6MTUyODkxMTYzNDM4NSwiYXBrUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmFuZHJvaWQuZ21zIiwiYXBrRGlnZXN0U2hhMjU2IjoiSk9DM1Vrc2xzdVZ6MTNlT3BuRkk5QnBMb3FCZzlrMUY2T2ZhUHRCL0dqTT0iLCJjdHNQcm9maWxlTWF0Y2giOmZhbHNlLCJhcGtDZXJ0aWZpY2F0ZURpZ2VzdFNoYTI1NiI6WyJHWFd5OFhGM3ZJbWwzL01mbm1TbXl1S0JwVDNCMGRXYkhSUi80Y2dxK2dBPSJdLCJiYXNpY0ludGVncml0eSI6ZmFsc2UsImFkdmljZSI6IlJFU1RPUkVfVE9fRkFDVE9SWV9ST00sTE9DS19CT09UTE9BREVSIn0.iCF6D2os8DYuDVOnt3zDJB2mSXnZjtWJtl_jzSDx5MrRC9A2fmFBZ6z5kpQZ2MiQ7ootj9WkHMgxqIhrX3dlh2POHAwkIS34ySjLVNsSPprE84eZgqSFLMEYT0GR2eVLHAMPN8n5R8K6buDOGF3nSi6GKzG57Zll8CSob2yiAS9r7spdA6H0TDH-NGzSdbMIId8fZD1dzFKNQr77b6lbIAFgQbRZBrnp-e-H4iH6d21oN2NAYRnR5YURacP6kGGj2cFxswE2908wxv9hiYNKNojeeu8Xc4It7PbhlAuO7ywhQFA81iPCCFm11B8cfUXbWA8l_2ttNPBEMGM6-Z6VyQ

And the FIDO MDS JWT:

eyJhbGciOiAiRVMyNTYiLCAidHlwIjogIkpXVCIsICJ4NWMiOiBbIk1JSUNuVENDQWtPZ0F3SUJBZ0lPUnZDTTFhdVU2RllWWFVlYkpIY3dDZ1lJS29aSXpqMEVBd0l3VXpFTE1Ba0dBMVVFQmhNQ1ZWTXhGakFVQmdOVkJBb1REVVpKUkU4Z1FXeHNhV0Z1WTJVeEhUQWJCZ05WQkFzVEZFMWxkR0ZrWVhSaElGUlBReUJUYVdkdWFXNW5NUTB3Q3dZRFZRUURFd1JEUVMweE1CNFhEVEUxTURneE9UQXdNREF3TUZvWERURTRNRGd4T1RBd01EQXdNRm93WkRFTE1Ba0dBMVVFQmhNQ1ZWTXhGakFVQmdOVkJBb1REVVpKUkU4Z1FXeHNhV0Z1WTJVeEhUQWJCZ05WQkFzVEZFMWxkR0ZrWVhSaElGUlBReUJUYVdkdWFXNW5NUjR3SEFZRFZRUURFeFZOWlhSaFpHRjBZU0JVVDBNZ1UybG5ibVZ5SURNd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTS1grcDNXMmoxR1Y0bFF3bjdIWE5qNGxoOWUyd0FhNko5dEJJUWhiUVRrcU12TlpHbkh4T243eVRaM05wWU81WkdWZ3IvWEM2NnFsaTdCV0E4amdUZm80SHBNSUhtTUE0R0ExVWREd0VCL3dRRUF3SUd3REFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCUmNrTkYrenp4TXVMdm0rcVJqTGVKUWYwRHd5ekFmQmdOVkhTTUVHREFXZ0JScEVWNHRhV1NGblphNDF2OWN6Yjg4ZGM5TUdEQTFCZ05WSFI4RUxqQXNNQ3FnS0tBbWhpUm9kSFJ3T2k4dmJXUnpMbVpwWkc5aGJHeHBZVzVqWlM1dmNtY3ZRMEV0TVM1amNtd3dUd1lEVlIwZ0JFZ3dSakJFQmdzckJnRUVBWUxsSEFFREFUQTFNRE1HQ0NzR0FRVUZCd0lCRmlkb2RIUndjem92TDIxa2N5NW1hV1J2WVd4c2FXRnVZMlV1YjNKbkwzSmxjRzl6YVhSdmNua3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWhBTExiWWpCcmJoUGt3cm4zbVFqQ0VSSXdrTU5OVC9sZmtwTlhIKzR6alVYRUFpQmFzMmxQNmpwNDRCaDRYK3RCWHFZN3k2MWlqR1JJWkNhQUYxS0lsZ3ViMGc9PSIsICJNSUlDc2pDQ0FqaWdBd0lCQWdJT1JxbXhrOE5RdUpmQ0VOVllhMVF3Q2dZSUtvWkl6ajBFQXdNd1V6RUxNQWtHQTFVRUJoTUNWVk14RmpBVUJnTlZCQW9URFVaSlJFOGdRV3hzYVdGdVkyVXhIVEFiQmdOVkJBc1RGRTFsZEdGa1lYUmhJRlJQUXlCVGFXZHVhVzVuTVEwd0N3WURWUVFERXdSU2IyOTBNQjRYRFRFMU1EWXhOekF3TURBd01Gb1hEVFF3TURZeE56QXdNREF3TUZvd1V6RUxNQWtHQTFVRUJoTUNWVk14RmpBVUJnTlZCQW9URFVaSlJFOGdRV3hzYVdGdVkyVXhIVEFiQmdOVkJBc1RGRTFsZEdGa1lYUmhJRlJQUXlCVGFXZHVhVzVuTVEwd0N3WURWUVFERXdSRFFTMHhNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUU5c0RnQzhQekJZbC93S3FwWGZhOThqT0lvNzhsOXB6NHhPekdER0l6MHpFWE1Yc0JZNmtBaHlVNEdSbVQwd280dHlVdng1Qlk4T0tsc0xNemxiS01SYU9CN3pDQjdEQU9CZ05WSFE4QkFmOEVCQU1DQVFZd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQWRCZ05WSFE0RUZnUVVhUkZlTFdsa2haMld1TmIvWE0yL1BIWFBUQmd3SHdZRFZSMGpCQmd3Rm9BVTBxVWZDNmYyWXNoQTFOaTl1ZGVPMFZTN3ZFWXdOUVlEVlIwZkJDNHdMREFxb0NpZ0pvWWthSFIwY0RvdkwyMWtjeTVtYVdSdllXeHNhV0Z1WTJVdWIzSm5MMUp2YjNRdVkzSnNNRThHQTFVZElBUklNRVl3UkFZTEt3WUJCQUdDNVJ3QkF3RXdOVEF6QmdnckJnRUZCUWNDQVJZbmFIUjBjSE02THk5dFpITXVabWxrYjJGc2JHbGhibU5sTG05eVp5OXlaWEJ2YzJsMGIzSjVNQW9HQ0NxR1NNNDlCQU1EQTJnQU1HVUNNQkxWcTBKZFd2MnlZNFJwMUlpeUlWV0VLRzFQVHoxcFBBRnFFbmFrUHR3NFJNUlRHd0hkYjJpZmNEYlBvRWtmWVFJeEFPTGtmRVBqMjJmQm5lajF3dGd5eWxzdTczcktMVXY0eGhEeTlUQWVWVW1sMGlEQk04U3RFNERpVnMvNGVqRmhxUT09Il19.eyJuZXh0VXBkYXRlIjogIjIwMTgtMDYtMTgiLCAibm8iOiA2MiwgImVudHJpZXMiOiBbeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDEzJTIzMDAwMSIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTUtMDUtMjAiLCAiaGFzaCI6ICIwNkxaeEo1bU51TlpqNDhJWkxWODE2YmZwM0E3R1Z0TzJPLUVlUTFwa1RZPSIsICJhYWlkIjogIjAwMTMjMDAwMSIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNS0wNS0yMCJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAxMyUyMzAwNjEiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE1LTEyLTIyIiwgImhhc2giOiAiZ1c4OVQxZzkyUmZXVG4yalhhUG8tc05TaW1nNHlwamdob2cwR25NRFA1Yz0iLCAiYWFpZCI6ICIwMDEzIzAwNjEiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTUtMTItMjIifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMTMlMjMwMDcxIiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNS0xMi0yMiIsICJoYXNoIjogIm5hREJvTndkNEExeGJLZ3FtSVBJbzM0RGNyb05PaWJqMkwtUUF0bE40TU09IiwgImFhaWQiOiAiMDAxMyMwMDcxIiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE1LTEyLTIyIn1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDEzJTIzMDA4NCIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTUtMTItMjIiLCAiaGFzaCI6ICJjNy1nT3gxTkFhTF9rcXVXRWl3V3VWWDQtaGhrZDNNZTY0REp3eFhQRXBvPSIsICJhYWlkIjogIjAwMTMjMDA4NCIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNS0xMi0yMiJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAxNCUyM0ZGRjEiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTExLTIyIiwgImhhc2giOiAiVlV0SWtQWHloa21GRmMxR2pUcmdGWDBnWnFkX1d4UHZzaTJnY3M5VF8zST0iLCAiYWFpZCI6ICIwMDE0I0ZGRjEiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJOT1RfRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE1LTA5LTI1In0sIHsic3RhdHVzIjogIlJFVk9LRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE2LTExLTIyIn1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDE0JTIzRkZGMiIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTYtMTEtMjIiLCAiaGFzaCI6ICJ1SDJoRTFUOHVJQmhuRjdGcm4zcUs4S0I4SktJLVpKYnBzUlBteWNIZmZzPSIsICJhYWlkIjogIjAwMTQjRkZGMiIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIk5PVF9GSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTUtMDktMzAifSwgeyJzdGF0dXMiOiAiUkVWT0tFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTYtMTEtMjIifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMTQlMjNGRkYzIiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNi0xMS0yMiIsICJoYXNoIjogIm1hUXloSW9kSWlqa1lpMkh5c3YtaGhWcC1qUzJILU5rWjBuZlplRElvUHM9IiwgImFhaWQiOiAiMDAxNCNGRkYzIiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiTk9UX0ZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNS0xMC0zMSJ9LCB7InN0YXR1cyI6ICJSRVZPS0VEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNi0xMS0yMiJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAxNSUyMzAwMDIiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTAxLTA4IiwgImhhc2giOiAiaThfd2N3MWFXRFJpRlVRZWtfbGIwNjhFdUxVY1NoTGpyeGNKVzBCOE92WT0iLCAiYWFpZCI6ICIwMDE1IzAwMDIiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTYtMDEtMDgifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMTUlMjMwMDA1IiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNy0wMi0wOCIsICJoYXNoIjogIlExZHFVck1wU3RwQkEyanJ0clJ6Rkt5amxWc2RpSWdyTU9teDV0dV9iWnc9IiwgImFhaWQiOiAiMDAxNSMwMDA1IiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE3LTAyLTA4In1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDE2JTIzMDAwMSIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTUtMDctMjEiLCAiaGFzaCI6ICJ1eWpESnBOSm9LTjlDMmhxOEktd2dVeGtkdXdBV1hRUUM5dXFrVHVHek5rPSIsICJhYWlkIjogIjAwMTYjMDAwMSIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNS0wNy0yMSJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAxNiUyMzAwMDMiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTAyLTEwIiwgImhhc2giOiAidFRlaGVMRDNHS0dqeGZidlYyZG9PX25VbGd5NHF5Y0o0MnhHQlpUTnZ4WT0iLCAiYWFpZCI6ICIwMDE2IzAwMDMiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJOT1RfRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE2LTAyLTEwIn1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDE2JTIzMDAxMCIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTYtMDItMTAiLCAiaGFzaCI6ICJSeWs0enpHSEV0M0hhOG5PQ1J3Wlo0VTh6VFdKeXhxTnFCNHpTcGRHR3k0PSIsICJhYWlkIjogIjAwMTYjMDAxMCIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIk5PVF9GSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTYtMDItMTAifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMTYlMjMwMDIwIiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNi0wMi0xMCIsICJoYXNoIjogInBYQVktQ05EV0tiVC1mVS1HclFGQWRyeERDbnM3R1U1Q3JaLVFEbm5TZEE9IiwgImFhaWQiOiAiMDAxNiMwMDIwIiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiTk9UX0ZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNi0wMi0xMCJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAxNyUyMzA0MDAiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE1LTEyLTI3IiwgImhhc2giOiAiOUg1N2ZHTGEyZjFhQ01wSC1xc1l0V01UX2lVVUh0YzhkOFNZb25BblRvOD0iLCAiYWFpZCI6ICIwMDE3IzA0MDAiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTUtMTItMjcifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMTklMjMwMDA1IiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNS0wNy0yMiIsICJoYXNoIjogImxmSmtOYUFHQWViWnpvTnpfMElaUXd4VlVnUHVYU1VJMnBiM0JsTmxZdms9IiwgImFhaWQiOiAiMDAxOSMwMDA1IiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE1LTA3LTIyIn1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDE5JTIzMTAwNSIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTctMDItMTAiLCAiaGFzaCI6ICJfWnRiaE5zc2tYdWQ2bXJhMjh5T1R5akxEelFVdkdsOUluLUZaYjJYaTQ0PSIsICJhYWlkIjogIjAwMTkjMTAwNSIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNy0wMi0xMCJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAxOSUyMzEwMDkiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE3LTAyLTEwIiwgImhhc2giOiAiS0J0bnZ1M0pjY1l0Q0NJZmR1VzFIV3p1TFZlclo5UlJCWWdyTWFCakIyND0iLCAiYWFpZCI6ICIwMDE5IzEwMDkiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTctMDItMTAifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMUIlMjMwMDAxIiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNi0wMS0wMSIsICJoYXNoIjogInBRVjJiUjktSU1EYUdGWkpDNkJLYXRmOTN0SVBUZlN2a2xUdkdMam44REE9IiwgImFhaWQiOiAiMDAxQiMwMDAxIiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiTk9UX0ZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNi0wMS0wMSJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAxRCUyMzAwMDEiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE3LTAzLTMxIiwgImhhc2giOiAiWEhjMzJVWGVmdnNQT1p6LUNOYU5fZFNYUFBYaW5EQ2JRekpqRTZaWWpSdz0iLCAiYWFpZCI6ICIwMDFEIzAwMDEiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJOT1RfRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE3LTAzLTMxIn1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDFEJTIzMDAwMiIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTctMDUtMDQiLCAiaGFzaCI6ICJhc2NVWGxwdzdDMHJjdFFGaENSNUViS25jLXNWTkxPUFlxd1AxM045Nmk4PSIsICJhYWlkIjogIjAwMUQjMDAwMiIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIk5PVF9GSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTctMDUtMDQifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMUQlMjMxMDAxIiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNy0wMy0yOCIsICJoYXNoIjogImJyWWI2azdacktkYzdBeDFRVEM4ZHd6Q3c5clYxSngxWkl4a3drREJPUTg9IiwgImFhaWQiOiAiMDAxRCMxMDAxIiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiTk9UX0ZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNy0wMy0yOCJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAxRSUyMzAwMDEiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTAzLTMxIiwgImhhc2giOiAiNnlycnJnTmRiaXZaN0ktRjRCUnBEeFZZN1hzRHE5WEJWdExydjFQd2dxUT0iLCAiYWFpZCI6ICIwMDFFIzAwMDEiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJOT1RfRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE2LTAzLTMxIn1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDFFJTIzMDAwMiIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTYtMDEtMTgiLCAiaGFzaCI6ICI2djdJQzNrMk1uUXNyNFhjWFh3V19zTnBRaS1VWm5LNWxrdWVIdXlKcGRFPSIsICJhYWlkIjogIjAwMUUjMDAwMiIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIk5PVF9GSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTYtMDEtMTgifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMUUlMjMwMDAzIiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNi0wMi0wNCIsICJoYXNoIjogIjZIZVNjeEFaWl91MEFnTzdkbWdvMDg4R0ZveWxOQld0VGIzQWNULUMyaGs9IiwgImFhaWQiOiAiMDAxRSMwMDAzIiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiTk9UX0ZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNi0wMi0wNCJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAxRSUyMzAwMDQiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTAyLTA0IiwgImhhc2giOiAiN2ZaRGMwRVJxNEZ1U1d6cEkxTGtwcnk5OFllYnp0NU55VThteUV1TWxoMD0iLCAiYWFpZCI6ICIwMDFFIzAwMDQiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJOT1RfRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE2LTAyLTA0In1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDFFJTIzMDAwNSIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTYtMDItMDQiLCAiaGFzaCI6ICJ4b1pzQmg1c3Z2aWNqcDdsODVFSEdyckRjUkFIeVhHeWZyVFpXNmlnMVl3PSIsICJhYWlkIjogIjAwMUUjMDAwNSIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIk5PVF9GSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTYtMDItMDQifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMUUlMjMwMDA2IiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNi0wMi0wNCIsICJoYXNoIjogImtxYV8tOXE4U21EWUpmeTRGb3FTZmpIWURpWmE3RFhOSjRPS3hrUnFxSHM9IiwgImFhaWQiOiAiMDAxRSMwMDA2IiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiTk9UX0ZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNi0wMi0wNCJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAxRSUyMzAwMDciLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTAzLTIxIiwgImhhc2giOiAiODR2ZHQwUno0VERfczZhQkpJaFNtQ1ZPSld0U2doSzhmRXpKcnVSMDl0TT0iLCAiYWFpZCI6ICIwMDFFIzAwMDciLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTYtMDMtMjEifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMjAlMjNBMTExIiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNi0xMS0yMiIsICJoYXNoIjogInhJRTVUZW9fTlJ3cGsxNUFMSURrVFhUdWN3dG9lMXlSenhYUzVCYkNzWFU9IiwgImFhaWQiOiAiMDAyMCNBMTExIiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiTk9UX0ZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNi0xMS0yMiJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAyMCUyM0EyMDEiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTAyLTEyIiwgImhhc2giOiAiaFdHNnhHMjB0TjZHTnU2c0NIZjBnNVo2WHRrRTNmRWFrazVwQXlqUDBZTT0iLCAiYWFpZCI6ICIwMDIwI0EyMDEiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJOT1RfRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE2LTAyLTEyIn1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDIwJTIzQTIwMiIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTYtMDItMTIiLCAiaGFzaCI6ICJ5SzRqVE1BSlFZMmwtV1dJNm1CWmdmQlpaTkpLZzE3VnhTcm9mT0xFWEhRPSIsICJhYWlkIjogIjAwMjAjQTIwMiIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIk5PVF9GSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTYtMDItMTIifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMjAlMjNBMjAzIiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNi0wMi0xMiIsICJoYXNoIjogIjBiS19DQ2ZDTWd0aWF5amVtOWU3cWtZQ3FiaGw5c3IwcGgzbWR5SUpfREE9IiwgImFhaWQiOiAiMDAyMCNBMjAzIiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiTk9UX0ZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNi0wMi0xMiJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAyMCUyM0EyMDQiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE1LTEyLTIyIiwgImhhc2giOiAiZWg3VjRwaU5fVTVCY19mbFBZMzg2RmNoUnc1VzN1QXh1MGo4M3FCMlkxbz0iLCAiYWFpZCI6ICIwMDIwI0EyMDQiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTUtMTItMjIifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMjAlMjNBMjA1IiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNi0wMi0xMiIsICJoYXNoIjogIlhlRk9pTWs2ajFoaE5hMm14WEdVaDJyenEtUWZ2TnBRNndFcDZWaFNNWmM9IiwgImFhaWQiOiAiMDAyMCNBMjA1IiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiTk9UX0ZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNi0wMi0xMiJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAyMCUyM0EyMDYiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTAyLTEyIiwgImhhc2giOiAiLTc0bjFKMmFtNWRqWGF0WW9IVGt5dnhhcGlRWEtVMU1DNEhuXzVGMEZRST0iLCAiYWFpZCI6ICIwMDIwI0EyMDYiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJOT1RfRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE2LTAyLTEyIn1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDIwJTIzQjIwNCIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTUtMTItMjIiLCAiaGFzaCI6ICJVQjk2dHdDX0h2cUpQWENOQjFhWHd5bHNnT0ZyV2dUYi15aE9KLW5ZSTJrPSIsICJhYWlkIjogIjAwMjAjQjIwNCIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNS0xMi0yMiJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAyOCUyMzAwMDEiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTAzLTIxIiwgImhhc2giOiAiQ2ZZOHItT1M2NmtYNEJNUkFZbkJVcVFHUzc0bEk2Vy03SDRzQ2FabEU4Zz0iLCAiYWFpZCI6ICIwMDI4IzAwMDEiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTYtMDMtMjEifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzAwMzElMjMwMDAxIiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNy0wMy0yMiIsICJoYXNoIjogImRhUnlaMUhKQjFtdlYwaEtESWx0OUxvcWhnU1Rwamo5Y3ZwT2NmVndWNVE9IiwgImFhaWQiOiAiMDAzMSMwMDAxIiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE3LTAzLTIyIn1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8wMDMxJTIzMDAwMiIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTctMDMtMjIiLCAiaGFzaCI6ICJVUEFoVHk1RnhFTEZNdUdOTm0zOFYxdEVEVzVacVc4MmpWMWRjLS02VDFrPSIsICJhYWlkIjogIjAwMzEjMDAwMiIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNy0wMy0yMiJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvMDAzNyUyMzAwMDEiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE3LTExLTI4IiwgImhhc2giOiAiRDRhU0JtYTJfTFdkV2ZpSkhnbW52OFRjMUVSNmZ0QUdVcXFUb2hFZ1pIZz0iLCAiYWFpZCI6ICIwMDM3IzAwMDEiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTctMTEtMjgifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzA5NkUlMjMwMDA0IiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNy0wMS0wNCIsICJoYXNoIjogIkFnTjJVbElLQTRXMDFuZ1dEZHlZWXNYVjQzX1cwcWhCVGQxYUNaTGdPSUU9IiwgImFhaWQiOiAiMDk2RSMwMDA0IiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE3LTAxLTA0In1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS8xRUE4JTIzODA4MSIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTctMDQtMDciLCAiaGFzaCI6ICJqVFZBVlNXR2ZONjN5SzZHQkFkNXhnTk1EYWF2eDR5dGZsN0EtUjg1QVRrPSIsICJhYWlkIjogIjFFQTgjODA4MSIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNy0wNC0wNyJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvNDc0NiUyMzMyMDgiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTA2LTA3IiwgImhhc2giOiAiRHV1RzRoeEJoZS1Kb3hPbjhTek9jZlcwbTVPNk1YTkIzdFZoc09xdTFjOD0iLCAiYWFpZCI6ICI0NzQ2IzMyMDgiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTYtMDYtMDcifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzQ3NDYlMjM1MjA2IiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNy0wMy0wOSIsICJoYXNoIjogIm9sQzZ6TjEyUDFpXzdVcUZwTG5mSFhBelVtbWthMVl5VWtfVl9Fd1pyOGM9IiwgImFhaWQiOiAiNDc0NiM1MjA2IiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE3LTAzLTA5In1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS80NzQ2JTIzRjgxNiIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTUtMTAtMTIiLCAiaGFzaCI6ICJQd2hjUkF4d2pReGx3cW9Xb0xoa0VhLTV1dk9tNElEUE13RkdMNWtMRENzPSIsICJhYWlkIjogIjQ3NDYjRjgxNiIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNS0xMC0xMiJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvNGU0ZSUyMzQwMDUiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE1LTA5LTE1IiwgImhhc2giOiAiaklGUnNwUGRGYkI2bW9GQnlHYnpTdWtfSDJNUGlxYU96ZFQxZ3pmbkJPYz0iLCAiYWFpZCI6ICI0ZTRlIzQwMDUiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJOT1RfRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE1LTA5LTE1In1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS80ZTRlJTIzNDAwNiIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTYtMDMtMTQiLCAiaGFzaCI6ICJPMmo0QzdGbHJ0dy1kZFZHbDFWY0NqZnZYYXFDY3c5blB3QjBIMFh6UEo4PSIsICJhYWlkIjogIjRlNGUjNDAwNiIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIk5PVF9GSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTYtMDMtMTQifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzRlNGUlMjM0MDA5IiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNi0wMy0xNCIsICJoYXNoIjogImV5TE1GNDQ1Y1BMX1RLc2NmWUdlWXJiLWJZWDAyRG5BZGlsdzBLTEdNTG89IiwgImFhaWQiOiAiNGU0ZSM0MDA5IiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiTk9UX0ZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNi0wMy0xNCJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvNGU0ZSUyMzQwMGEiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTAzLTE0IiwgImhhc2giOiAiVllxaWRHOFk4ZDlENkY3QXJlUWlpck9VVXdLWmoxNTdFakRkVWlnRkNvcz0iLCAiYWFpZCI6ICI0ZTRlIzQwMGEiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJOT1RfRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE2LTAzLTE0In1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS80ZTRlJTIzNDAwYiIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTYtMDMtMTQiLCAiaGFzaCI6ICJEU2VfR2U4QkotZXhWV0RReDRQU19lZGRFZWJ5Tm4wUUtmRlIxZVRTQlN3PSIsICJhYWlkIjogIjRlNGUjNDAwYiIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIk5PVF9GSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTYtMDMtMTQifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhLzRlNGUlMjM0MDEwIiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNi0wMy0xNCIsICJoYXNoIjogIjBoSUliUjRqZWdQZFhDVjNGZi1ibGMwdS1SbVlaekFSdWo0QVViS1RHcXc9IiwgImFhaWQiOiAiNGU0ZSM0MDEwIiwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiTk9UX0ZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNi0wMy0xNCJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvNGU0ZSUyMzQwMTEiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE2LTAzLTE0IiwgImhhc2giOiAibVVLOHJVRGtHQVNqcDVDNjFQUUNFbVN4Um9OSTVpWTJjWkNuRDB6eTlnZz0iLCAiYWFpZCI6ICI0ZTRlIzQwMTEiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJOT1RfRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE2LTAzLTE0In1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS85ek1VRmFvVEU4MmlXdTl1SjROeFo4IiwgImhhc2giOiAiRUNTLWp0cnJIMmgySkxGeHExSGVJN2V0MldXRTh0VjZHc1IzVTl2c2txcz0iLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE3LTExLTI4IiwgImF0dGVzdGF0aW9uQ2VydGlmaWNhdGVLZXlJZGVudGlmaWVycyI6IFsiOTIzODgxZmUyZjIxNGVlNDY1NDg0MzcxYWViNzJlOTdmNWE1OGUwYSJdLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTctMTEtMjgifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhL2JiRVBtZDM2aHJvc2lWYnhCWmNHN2YiLCAiaGFzaCI6ICJHV0FLbEtmVmwxMC1oMmlQQl9uY2hiZWZhcnJiZDFmVG9YSXYxWThjS1dZPSIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTctMDItMTEiLCAiYXR0ZXN0YXRpb25DZXJ0aWZpY2F0ZUtleUlkZW50aWZpZXJzIjogWyI5NDFiNjczODRmZjAzMzMwYjcwZGNjYTU4ZjcyMTYzMmYwNDcyNmQyIl0sICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNy0wMi0xMSJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvQnoyRExHdHhQYzRkU0RGa2VaNkJUQyIsICJoYXNoIjogIllpNzI3SUUtRVJkbEJIT2VyUE54cmExaTZrTnJqalBaX2h3NURkX3FRQm89IiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNy0wMS0yNCIsICJhdHRlc3RhdGlvbkNlcnRpZmljYXRlS2V5SWRlbnRpZmllcnMiOiBbIjQxODM3N2UyMTNkYjE0YWJjNjUwOWRiNWUxMGM5NTk4YjQyZjkyZWEiXSwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE3LTAxLTI0In1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS9EQUI4JTIzMDAxMSIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTUtMTAtMDIiLCAiaGFzaCI6ICJ5NGlPSlp1S0x2MUVYa3VXQVFrWFF1QXgzbmI4THZCdFd4OUpMcWlWQjY4PSIsICJhYWlkIjogIkRBQjgjMDAxMSIsICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNS0xMC0wMiJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvREFCOCUyMzEwMTEiLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE1LTEyLTIzIiwgImhhc2giOiAiYW51TVFoWnpLUnpGSEoyd1ppWVV2RzFyUXFtODd1YU5DeFJNUHh3RFZ5ST0iLCAiYWFpZCI6ICJEQUI4IzEwMTEiLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTUtMTItMjMifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhL2VTN3Y4c3VtNGp4cDdrZ0xRNVFxY2ciLCAiaGFzaCI6ICJSRHp3dFlDbFdVeWFyVS03WXNLYzg3U2JKUktydG44Q3pIdWlhMjNQRm53PSIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTctMDMtMTQiLCAiYXR0ZXN0YXRpb25DZXJ0aWZpY2F0ZUtleUlkZW50aWZpZXJzIjogWyJkNWRiNGRkNDhmZTQ2YWZkOGFmOGYxZjdjZmJkZWU2MTY0MGJiYmNjIiwgIjU1NDY0ZDViZWE4NGU3MDczMDc0YjIxZDEyMDQ5MzQzNThjN2RiNGQiXSwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE3LTAzLTE0In1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS9GYkZaMktGdmk5QkNyVWRTc1pKRFJlIiwgImhhc2giOiAiVWxLdFFJeWhpdXc0VHoySHNfVTcwRGlib0ZzVi1BYlZLTnhLVE5VTWpzST0iLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE3LTAyLTA4IiwgImF0dGVzdGF0aW9uQ2VydGlmaWNhdGVLZXlJZGVudGlmaWVycyI6IFsiZDNhMTU5OGMwOWRjZDUxMTQyOTczZjFiYjdjOGJkNjUyZTkzYjEwNSJdLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTctMDItMDgifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhL0pLUDVDaURlaGRNTVB3dEc1aTd0bzUiLCAiaGFzaCI6ICJCTWI2VTlLSWxBTGVuUUJvMktGXzNJZ001ZGRpT0tmSU8wSVc1U19yODN3PSIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTctMDMtMDIiLCAiYXR0ZXN0YXRpb25DZXJ0aWZpY2F0ZUtleUlkZW50aWZpZXJzIjogWyJhNWEzNTMwZTAzYTBmMjExODM5OWFjMGI2YzNjOWQ1NTJhMGQzNGY4Il0sICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNy0wMy0wMiJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvbU5TUEx1emd5RGFWQXpVRzdIQUVOOSIsICJoYXNoIjogImVjWmN4SVhwMjRYeVliR0lkYm11N05oSmc0RzNwNnF4UVRhUVcwOG53cmM9IiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxOC0wNC0xMyIsICJhdHRlc3RhdGlvbkNlcnRpZmljYXRlS2V5SWRlbnRpZmllcnMiOiBbIjJkMDE4OGI5ZTI1NTJmZWUwYWI2YTYxMjY0MWRlOTY2ODQxZWJlMmIiLCAiMWVhODljOTE2ZDJhYzNjZjI2MmI3ODMyMjk5YzQ4ZDhiNDhjZTMyMyJdLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJOT1RfRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE4LTA0LTEzIn1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS9OOVVvN1c0Y05udmE3Mkxxd0dKUm5kIiwgImhhc2giOiAiZVZkS0VsWDJqZXg0X1JoRWVxMXVpYjE4RnBPcGYwUUNQNDhyUVgxYkVOYz0iLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE3LTAyLTIwIiwgImF0dGVzdGF0aW9uQ2VydGlmaWNhdGVLZXlJZGVudGlmaWVycyI6IFsiNmJhYjE5YzZjMDk3ZjE5MDYwY2U1NDA0MDAwMzgwYzMyZmE2YThlNiJdLCAic3RhdHVzUmVwb3J0cyI6IFt7InN0YXR1cyI6ICJGSURPX0NFUlRJRklFRCIsICJ1cmwiOiAiIiwgImNlcnRpZmljYXRlIjogIiIsICJlZmZlY3RpdmVEYXRlIjogIjIwMTctMDItMjAifV19LCB7InVybCI6ICJodHRwczovL21kcy5maWRvYWxsaWFuY2Uub3JnL21ldGFkYXRhL3VQVGZxQVBiYVpzQ3QydnlldVRqeksiLCAiaGFzaCI6ICJ2U1EybFZnQTZKMW84MEl0MUMteW81WVhpM0tBbW15RlJyVmRvSWI1TF9jPSIsICJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjogIjIwMTctMTEtMjgiLCAiYXR0ZXN0YXRpb25DZXJ0aWZpY2F0ZUtleUlkZW50aWZpZXJzIjogWyI2Y2Q5OWQ4YjBhYmZhNmE0Mzc4MTM4YTE0NzVmN2U0NmRmMjE3YTI1IiwgIjdhOGZlMzdhNDJiYmYyYTViM2U2NTc0ZDZmMDRiZGJjNTVlNTkwNDciLCAiYzEwYmM0YzZmNjE0YjYzMzcxZDkyOTU5NmVkZWRkZTNlNDU4NDA0ZCIsICI3NmU0N2I0N2UzMjgxNGFhYTZhODdjMjgwY2ZjYmQ1Mjc4ODFhNDA0Il0sICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxNy0xMS0yOCJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEvVjRmekFkVkZEalE4eGd5NHZrMkRzUSIsICJoYXNoIjogIkQwTGt3OEg2X0E2UFU2SGlSN2NuVnZsSTdOdkFvU0lEOVpGdFlPMGJwbXM9IiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNy0wMi0wOCIsICJhdHRlc3RhdGlvbkNlcnRpZmljYXRlS2V5SWRlbnRpZmllcnMiOiBbImM4ODg3MWE0MzhlZjk3YzRkODMyMDdkNmYxNjExMzkyN2FmOGVmM2EiXSwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE3LTAyLTA4In1dfSwgeyJ1cmwiOiAiaHR0cHM6Ly9tZHMuZmlkb2FsbGlhbmNlLm9yZy9tZXRhZGF0YS9XUkQ4ejJXUnk5TGU0TmVtR1VLNnZBIiwgImhhc2giOiAiMmJ6Q1ZCZVBjSHV3azE3Y250NVVxQktvamRhSmJZVUtpakY0dG1FcTNXcz0iLCAidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6ICIyMDE4LTAyLTA5IiwgImF0dGVzdGF0aW9uQ2VydGlmaWNhdGVLZXlJZGVudGlmaWVycyI6IFsiNWZiYzRiYTc1MzA1MjE4N2FhYjNjNzQxZDFmOWVjNmZiM2M0ZDg3NSIsICIyZWI5ZmYzNTcyZjY3NjI4ZDEyOTFhM2I1NzkyNGY4MThhYWQ5ZTcyIl0sICJzdGF0dXNSZXBvcnRzIjogW3sic3RhdHVzIjogIkZJRE9fQ0VSVElGSUVEIiwgInVybCI6ICIiLCAiY2VydGlmaWNhdGUiOiAiIiwgImVmZmVjdGl2ZURhdGUiOiAiMjAxOC0wMi0wOSJ9XX0sIHsidXJsIjogImh0dHBzOi8vbWRzLmZpZG9hbGxpYW5jZS5vcmcvbWV0YWRhdGEveU1VRkNQMnF6anNZc2JIZ0VZWlNWOSIsICJoYXNoIjogIjZKbllrejRURDh1d3NIZVFTcDgtX1lGbWhkQS1wMGthTkhfN21xQl8wY3M9IiwgInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiAiMjAxNy0wMy0yMyIsICJhdHRlc3RhdGlvbkNlcnRpZmljYXRlS2V5SWRlbnRpZmllcnMiOiBbImZiZWMxMmM0Mjg3NzRkMzFiZTRkNzcyMzY3NThlYTNjMDQxYTJlZDAiXSwgInN0YXR1c1JlcG9ydHMiOiBbeyJzdGF0dXMiOiAiRklET19DRVJUSUZJRUQiLCAidXJsIjogIiIsICJjZXJ0aWZpY2F0ZSI6ICIiLCAiZWZmZWN0aXZlRGF0ZSI6ICIyMDE3LTAzLTIzIn1dfV19.XUDpXgWFEy2r2vvJVsk3pxADqu53nGsiF36F6q9aZFqJ_0b6X0eTS_xUggV61vFgX3_FLYtxpwJlBSSdw1__yQ

See also: auth0/node-jsonwebtoken#314

Add JWK(s) support?

Are you interested in supporting JSON web keys? There seem to be people who want it (auth0/node-jsonwebtoken#43).

I wrote the jws-jwk module to add such support, but it would be better to have the functionality built in for the issue I referenced.

If you want this functionality added, I can generate a pull request for it. I just do not want to spend the time if you have no interest.

Support (RFC7797) Unencoded Payload Option

RFC7797 defines an extension to JSON Web Signatures to allow unencoded payloads.

Additional features

Recommended API Changes

Add opts.detached

Default: false. When opts.detached === false, the payload is omitted from the payload. The separators remain where it would usually be. E.g.,

eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..A5dxf2s96_n5FLueVuW1Z_vh161FwXZC4YLPff6

Add opts.header.b64

Default: true. When b64 is false, the payload will not be encoded prior to signing.

Since, unencoded and detached are most useful together for large bodies, we would stream the data to sign. This would require a change to jwa in order to support this.

Signature verification (PS256) succeeds in Node.js but fails in jwt.io debugger

I wrote a test script with which I'm signing and then verifying a JWT with the PS256 algorithm.

My code verifies the JWT successfully, but the verification fails in the jwt.io debugger.

This only happens when using PS256. There are no issues when I use RS256 instead.

I'm using [email protected].

Am I doing anything wrong?

I generated my keys with:

openssl genpkey -algorithm RSA -out private_key2.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in private_key2.pem -out public_key2.pem

Code:

const { join } = require('path');
const { readFileSync } = require('fs');
const jws = require('jws');

const ALG = 'PS256';

/**********
 * SIGNING
 **********/

const PRIVATE_KEY_PATH = join(__dirname, './keys/private_key2.pem');

const privateKey = readFileSync(PRIVATE_KEY_PATH).toString();

const payload = {
  foo: 'bar',
};

const token = jws.sign({
  header: { alg: ALG },
  payload,
  privateKey,
})

console.log('Token:');
console.log(token);

/************
 * VERIFYING
 ************/

const PUBLIC_KEY_PATH = join(__dirname, './keys/public_key2.pem');

const publicKey = readFileSync(PUBLIC_KEY_PATH).toString();

const result = jws.verify(token, ALG, publicKey);
if (result) {
  console.log('Verification successful.');
} else {
  console.error('Verification failed.');
}

Private key:

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDPR8CD/9V9fddR
vMk590JtuU4hPT9iPD/mYeWdvUTbkN2iPpg6LDADBntz8I9CzThCkgHmDQhh49Qz
AONiHfyHhKT6HHIBS78wGWfhE9ueFtkv19xisvFJTDO6IllGFMiioj8AkvOJwaY+
5ZKSFG32V0gMaglNSNTOh5KK6DsxgdH2KfMzn6uFwJkvsz1qwPiINu/rqvOQPOIK
JCbNHBOg/SvhPWBSEFDC9AkLm3ajhGAcnSlWi0KgUFz7iHuUR6s4GLdkc40uAooY
ExEWsZyoByT18tXln2hPAvE1Ata2PSbtLHuwvMQt4vzZi80K4BXqOiqvNMo1A1aT
oSQnmOwtAgMBAAECggEAPpHTPEVS5aHCCItrVtMbu1FvkzsQ0g+L3nh4vqfujDTr
olkwzIagK5meVH4uUKTwMbAvYIlYmWwTlx3ShcC1hRb2UgWaKGf8G4HfyKKc7djJ
0NZhUW3gxhZ5mttZhX0qn2VIjVzOpSvOijf0iaIfG3h3aD/t9OViT8G+6610iNmz
Oygmi9kQaBAS2A2sLSSMhdyddIPEpZ8QOHwGCRvBXWO100BCV9ROQzYxW+U9VPaJ
I0tXDL1L1H7y1EbxccPfOsfUPMtF9LQWQZ6ksJuSRwkBAnfKpzexguph29sLDjCQ
X23rQN/NwiU+zRmn+cW7VqkZsbSqucP9t+d19UdWpQKBgQDn9sThxAZvx4OS0noD
AWJX5CliDNlagmLqr4c0QoYI+fPL7FcK9tQYUZ869jnebX7UPHTuDhMoIvWknZbB
QhoogpRoX+XFtxzPwjtBBGc5TYacYnOR4xPSjvDlIrY7FQiH8TgpAGzenSBiD8O0
xW4zSaHLUDHEMFEyPq8tdMmBewKBgQDkwjUnVMPlA9AOD+KQNXgf2kV9z0ZA5idt
9WcsXsxpO2W6S0ntkr29Yr3VuuuJTRH7Fm+bPDJ6C1bfZ746hn3iLMZbMxgGVEf/
cN0nNXjfG5G7EEIU9WFges1I5rec/5W38kIco6soP36Qj5HcUBXt6AHy3k1IbEL2
84Bp1SZ0dwKBgF19mhCcXzPCKAePCVoYvrhJ31wDbb8K+i84m7e2cCtCAr7X/KUQ
op9Clni/MMezPgDwdPhVd+cfX/3+/fnaWIynRIVk0UkE6nnaAOPNkIUJ+A0jqQzN
hvnAXtsbSHM7oPqZgFcWMsrubVTYobpEMIw/SxSUt9oo1zD3Dse1YFntAoGBAIAL
AIuKU7f9gVhNpehINXvGxfzcpxsueEWBBgX87fe9CnzTJYc4CsJV4aIfZTVOEVF0
xnWipTJQ5IhZ3k2N+CpAG6ryl3D7fe1J9E+9C3H+UXzeZc6rZp0FP6Cdm4riOKBk
loLHTcdSevpZkjA6F3w5z9Vsft+Z0YW+2FLkvwiTAoGAdjUYcGTaEhGNtHQszAeY
2VbeVHwgnajKhaZpKMNTVp/AFgeS5k1lSATlT5wQHD3OAhUn+NAEwUOUBBWOpg+i
jML8loplEcVmdHkfGFsrIvzFFIIXQOWy77s/McTCh2jLkLYO8kIOrGy08JBiZnQ/
Ki/HFS/2yaUbG6UdH8FFp2g=
-----END PRIVATE KEY-----

Public key:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz0fAg//VfX3XUbzJOfdC
bblOIT0/Yjw/5mHlnb1E25Ddoj6YOiwwAwZ7c/CPQs04QpIB5g0IYePUMwDjYh38
h4Sk+hxyAUu/MBln4RPbnhbZL9fcYrLxSUwzuiJZRhTIoqI/AJLzicGmPuWSkhRt
9ldIDGoJTUjUzoeSiug7MYHR9inzM5+rhcCZL7M9asD4iDbv66rzkDziCiQmzRwT
oP0r4T1gUhBQwvQJC5t2o4RgHJ0pVotCoFBc+4h7lEerOBi3ZHONLgKKGBMRFrGc
qAck9fLV5Z9oTwLxNQLWtj0m7Sx7sLzELeL82YvNCuAV6joqrzTKNQNWk6EkJ5js
LQIDAQAB
-----END PUBLIC KEY-----

Decode jws header

Is it possible to decode the header without knowing the algorithm?

Modifying payload hash causes crash

Original Token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzaXRlIjoidGVzdCIsImlhdCI6MTUwNzE1Nzg1M30.imUNKrBoBpoYRrpNaar7aPUTEHOCyzeQhwM488WzJb8

Mod Token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eMODIFYINGyJzaXRlIjoidGVzdCIsImlhdCI6MTUwNzE1Nzg1M30.imUNKrBoBpoYRrpNaar7aPUTEHOCyzeQhwM488WzJb8

undefined:1
y�ͥє��ѕ�Ј����Ј������������
^

SyntaxError: Unexpected token y in JSON at position 0
    at JSON.parse (<anonymous>)
    at Object.jwsDecode [as decode] (/Users/fran/Projects/testjwtissue/node_modules/jws/lib/verify-stream.js:71:20)
    at Object.module.exports [as decode] (/Users/fran/Projects/testjwtissue/node_modules/jsonwebtoken/decode.js:5:21)
    at middleware (/Users/fran/Projects/testjwtissue/node_modules/restify-jwt-community/lib/index.js:70:24)

Matching jwt token against a regex

Hey Guys,

We are facing some issues with the jsonwebtoken library when we create our own token following the JWT standards (using C language). Unfortunately the official C library doesnt compile well in our Windows environment.

After debugging for days we came to the conclusion that the regex used in the jws library verify-stream.js file does not allow for equals sign (=), hence the regex validation fails.

Currently the regex looks like as follow -

const JWS_REGEX = /^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/;

Suggested change is to include the (=) sign as well -

const JWS_REGEX = "^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*$";

Thanks

Failure to correctly serialize ECDSA signatures

When serializing an ECDSA signature, the correct procedure is to form two fixed-length bigints, each of octet length equal to the length of the representation of the prime which the curve is defined modulo to.

This package does not do so. E.g., try doing:

> jws.sign({header:{alg:'ES256'},payload:'testing',privateKey:key}).split('.')[2].length
94
> jws.sign({header:{alg:'ES256'},payload:'testing',privateKey:key}).split('.')[2].length
95

where

key = '-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIN8L9YcwuTY6DotH/gc8xP+oemVRj/uTQO6GjnLjSlgIoAoGCCqGSM49\nAwEHoUQDQgAE4nnUjvSzANAZ4l4wrWgpCPqEMDGoCPnEpm8093dDh6Uoww62quMA\nnLCpUSU56HuL5F0dHwuRXOdbQqo9P3hR6g==\n-----END EC PRIVATE KEY-----\n';

The length of the final part should always be the same, regardless of the numerical value of r or s. (In this case, ((4 * 64) + 2) // 3 == 86, so...I'm fairly confused by what this package is doing exactly.

UTF8 encoding problem

Your library is used by node-jsonwebtoken, and when it signs the token using your library it seems that it breaks the payload if there is an UTF8 character in the payload.
When I retrieve the token and decode it, and when I parse with JSON.parse() I get 'Unexpected token' error if the payload contained UTF8 chars.
In my case it was char 'ć' .
Can you verify?

RS256 keys do not create signatures causes runtime error

this is similar to issue #15: #15

No matter how I slice it, Reading the key from a file, adding it to code directly, removing \n line terminations, the RS256 encryption does not work correctly. For instance, reading the file directly:

Here's the value of the key

-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAizF1eqrBZ05SwnhKV+y5gvcuSVOtUkvMElNz9Ry/wx791fYi
Qdi/bRdWUh0MGfbLsQvZ6SVRIa3jfdgkdVRmLh7BvCj11SWbwDUJy/p1XzrkW2Va
L/u/Mmr/NR2BD/YdjEuShP31yMT7DDkKdYWvfuNc+mfDg+2H/q35dYHjgVGRC
jrmADA5tH0VSYp6Rw13T6iheBdB1dKNSuZkFTXCznEFGMFepAh6tWLOrGkbHWC3L
nPdj35F2LaoLZGGNCZxcLjk6tth0iNKbIwW1XrG6TAsNO0VqV6sK1adM3QTy404M
ib3UezZfFyo7pQ1E6+QPtvj6dGWZKQYMkvAC3wIDAQABAoIBAFoaBvkDxbQQoEPg
SAeIZkGfreercdt+0zfdq4c0N/GfgyLYdC55ltiQLcFzqhy4g/w0NrfT/yO1Azi4
DEmi+43JPRGG1jNGZ/7Qlmni0810OtPq1KmQ5aBGYLNKSPxDDbd+R/csychPsk6k
MeAHPOy3yndFZfGSWqB/PFgPsXQ7daV2+DmbXi7TPTsMq9dHQwBREvVGtiuviN1D
6lfpDw1BFUB68N3ptVYmOxlDeQId7s6TIjA2Xcltk6WRrv/VTaHpvtk0m8nZgVSy
PCasoGV8VVa5Wg/gD7fVJEuWFOZxUiURP9OGwrfALErLIUchozZu3wiJh9nZ6gig
Lh6jz4ECgYEAy+n9Aagap9vWq+rJ7xVlghkwPdkX0nyf4TVowmtwA+/aNcU6iybt
hrQWRiRhK+XI1BGWwvsbQbLQxoVxBFGYmKlkOlffg7Gdm4FtMEpv4oE2ERIxWBhn
LMzxWyHMVYvKE+2THnS2ToUTUp7/daCCsC1JqGIdOpu1kEaYeI+QYJ8CgYEArr9a
T7xyta6gCr092V9LpUkn0Mq8JoEo4DQ3mmbqyk4lFTYGklXQPdvpY/qfkUGwkV0Q
C1JQ+QbtLYRbo0vkr6j+GzGTojwnXhA9QL5/5mqIwcMCdBuC6UiIvv7a+zNJHuw/
Z7tzRe7IFDSuX2TjWIzkBv0jVwT88EdaZvYB9cECgYEAm3s/2mqGYKWEqzNsY+uJ
qchw+0e0HV+/PKZPyabIE4hodwV63S2CgWqBbVxB54nfNqxuqx9yqgahoC2RfjyF
QSov7TihijX9OdxXGDI525iwVBXuIAEDcqqWAenkdvoOzGEjA170vyxDDoWDvfn0
jEcL2eNt7AlcSLU7fvngmXsCgYAPZf9ATXvSNKwXpitgDzysOPEQPf0sa289qnxH
18/SueYco2Ea3gL2oH1FeR08gIxdktTKGpvWBd06iJJGpnZlYD/cB5dZ0XEqocW0
AdVlaXfZkySRNKdphSG/qteDETbdSbuz+eZcZ6LaA43QBJpElaIMHtQHQ7oix
z/XGQQKBgFWUjQ54vEWwuzb+0gsB2mf/QCL+anhktLy/v39OpkuUQQPZqSG31dPw
K9PNDxHECrpjSozdFhd21VApLXcLceh5tovKu+urrjAvPE7Da61LBHfqIa8dpSA0
epmPVSMGK69/XoKx9wZDaxEnoHg0vykY2C0pYUBpR8aKLYQoTDqN
-----END RSA PRIVATE KEY
 post: function() {
    var date, expiration, nonce, ref, ref1, secret, signature, userId;
    secret = fs.readFileSync('/Users/Patrick_/beautywire_api/beautywire.pem');
    userId = (ref = this.bodyParams) != null ? ref.userId : void 0;
    nonce = (ref1 = this.bodyParams) != null ? ref1.nonce : void 0;
    date = new Date(new Date().setHours(24 * 7 * 2)).toISOString();
    expiration = new Date(new Date(new Date().setHours(24 * 7 * 2)).toISOString());
    console.log(secret.toString());
    signature = jws.sign({
      header: {
        alg: 'RS256',
        typ: 'JWT',
        kid: Config.appLayerKeyId,
        cty: "layer-eit;v=1"
      },
      payload: {
        prn: userId,
        nce: nonce,
        exp: expiration
      },
      secret: secret.toString()
    });
    return {
      statusCode: 201,
      body: {
        success: true,
        data: {
          identityToken: signature
        },
        message: "Here's your token - have fun"
      }
    };
  }

W20160415-14:00:45.945(-7)? (STDERR) 140735103415040:error:0906D066:PEM routines:PEM_read_bio:bad end line:../deps/openssl/openssl/crypto/pem/pem_lib.c:804:
W20160415-14:00:45.998(-7)? (STDERR) Error: SignFinal error
W20160415-14:00:45.998(-7)? (STDERR) at Sign.sign (crypto.js:426:27)
W20160415-14:00:45.999(-7)? (STDERR) at Object.sign (/Users/Patrick_/beautywire_api/node_modules/jws/node_modules/jwa/index.js:54:45)
W20160415-14:00:45.999(-7)? (STDERR) at Object.jwsSign as sign
W20160415-14:00:46.000(-7)? (STDERR) at Object.App.api.addRoute.post as action

Removing \n:

I20160415-14:07:26.235(-7)? -----BEGIN RSA PRIVATE KEY-----MIIEowIBAAKCAQEAizF1eqrBZ05SwnhKV+y5gvcuSVOtUkvMElNz9Ry/wx791fYiQdi/bRdWUh0MGfbLsQvZ6SVRIa3jfdgkdVRmLh7BvCj11SWbwDUJy/p1XzrkW2VaL/u/Mmr/NR2BD/YdjEuShP31yMT7DDkKdYWXNIvfuNc+mfDg+2H/q35dYHjgVGRCjrmADA5tH0VSYp6Rw13T6iheBdB1dKNSuZkFTXCznEFGMFepAh6tWLOrGkbHWC3LnPdj35F2LaoLZGGNCZx1XrG6TAsNO0VqV6sK1adM3QTy404Mib3UezZfFyo7pQ1E6+QPtvj6dGWZKQYMkvAC3wIDAQABAoIBAFoaBvkDxbQQoEPgSAeIZkGfreercdt+0zfdq4c0N/GfgyLYdC55ltiQLcFzqhy4g/w0NrfT/yO1Azi4DEmi+43JPRGG1jNGZ/7Qlmni0810OtPq1KmQ5aBGYLNKSPxDDbd+R/csychPsk6kMeAHPOy3yndFZfGSWqB/PFgPsXQ7daV2+DmbXi7TPTsMq9dHQwBREvVGtiuviN1D6lfpDw1BFUB68N3ptVYmOxlDeQId7s6TIjA2Xcltk6WRrv/VTaHpvtk0m8nZgVSyPCasoGV8VVa5Wg/gD7fVJEuWFOZxUiURP9OGwrfALErLIUchozZu3wiJh9nZ6gigLh6jz4ECgYEAy+n9Aagap9vWq+rJ7xVlghkwPdkX0nyf4TVowmtwA+/aNcU6iybthrQWRiRhK+XI1BGWwvsbQbLQxoVxBFGYmKlkOlffg7Gdm4FtMEpv4oE2ERIxWBhnLMzxWyHMVYvKE+2THnS2ToUTUp7/daCCsC1JqGIdOpu1kEaYeI+QYJ8CgYEArr9aT7xyta6gCr092V9LpUkn0Mq8JoEo4DQ3mmbqyk4lFTYGklXQPdvpY/qfkUGwkV0QC1JQ+QbtLYRbo0vkr6j+GzGTojwnXhA9QL5/5mqIwcMCdBuC6UiIvv7a+zNJHuw/Z7tzRe7IFDSuX2TjWIzkBv0jVwT88EdaZvYB9cECgYEAm3s/2mqGYKWEqzNsY+uJqchw+0e0HV+/PKZPyabIE4hodwV63S2CgWqBbVxB54nfNqxuqx9yqgahoC2RfjyFQSov7TihijX9OdxXGDI525iwVBXuIAEDcqqWAenkdvoOzGEjA170vyxDDoWDvfn0jEcL2eNt7AlcSLU7fvngmXsCgYAPZf9ATXvSNKwXpitgDzysOPEQPf0sa289qnxH18/SueYco2Ea3gL2oH1FeR08gIxdktTKGpvWBd06iJJGpnZlYD/cB5dZ0XEqocW0AdVlaXfZkySRNKdphSG/qteDETbdSbYgnuz+eZcZ6LaA43QBJpElaIMHtQHQ7oixz/XGQQKBgFWUjQ54vEWwuzb+0gsB2mf/QCL+anhktLy/v39OpkuUQQPZqSG31dPwK9PNDxHECrpjSozdFhd21VApLXcLceh5tovKu+urrjAvPE7Da61LBHfqIa8dpSA0epmPVSMGK69/XoKx9wZDaxEnoHg0vykY2C0pYUBpR8aKLYQoTDqN-----END RSA PRIVATE KEY
W20160415-14:07:26.236(-7)? (STDERR) 140735103415040:error:0906D06C:PEM routines:PEM_read_bio:no start line:../deps/openssl/openssl/crypto/pem/pem_lib.c:696:Expecting: ANY PRIVATE KEY
W20160415-14:07:26.296(-7)? (STDERR) Error: SignFinal error
W20160415-14:07:26.296(-7)? (STDERR) at Sign.sign (crypto.js:426:27)
W20160415-14:07:26.296(-7)? (STDERR) at Object.sign (/Users/Patrick_/beautywire_api/node_modules/jws/node_modules/jwa/index.js:54:45)
W20160415-14:07:26.297(-7)? (STDERR) at Object.jwsSign as sign

  post: function() {
    var date, expiration, nonce, ref, ref1, secret, signature, userId;
    secret = fs.readFileSync('/Users/Patrick_/beautywire_api/beautywire.pem');
    userId = (ref = this.bodyParams) != null ? ref.userId : void 0;
    nonce = (ref1 = this.bodyParams) != null ? ref1.nonce : void 0;
    date = new Date(new Date().setHours(24 * 7 * 2)).toISOString();
    expiration = new Date(new Date(new Date().setHours(24 * 7 * 2)).toISOString());
    console.log(secret.toString().replace(/\n/g, ''));
    signature = jws.sign({
      header: {
        alg: 'RS256',
        typ: 'JWT',
        kid: Config.appLayerKeyId,
        cty: "layer-eit;v=1"
      },
      payload: {
        prn: userId,
        nce: nonce,
        exp: expiration
      },
      secret: secret.toString().replace(/\n/g, '')
    });
    return {
      statusCode: 201,
      body: {
        success: true,
        data: {
          identityToken: signature
        },
        message: "Here's your token - have fun"
      }
    };
  }

Following the other issue, exactly from your response, this should create a signed key.

Does JWS support verification with a PKCS#8 public key?

I know that JWS can support reading a PEM key using the PCKS#1 encoding - a public key looks like this:

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAwEYqf3HAL+h0CbcM6cnVfT6hDw0nNPkLYKld54qRYhJa+txnI8so
bIhP4/1l3TnNZldFFOatRlZAxuNG8Dk4L/QQmDeIsOkYQ5oiytSCbUrJv44aOPjL
G72XhVOaOLMT2vp/guOVAjTYOyF83asoOpPVtFeiBHhKudMrpPzeq3qwGMxfVVPy
NlztFjnTlkAKMtkbkwcpzdTn4y/pDo47+LgkDckReoqTIK4Z1bp86Oa6eBOa7/6w
hIXG3aCQiMQfJUBEBRA7mmV4g+jNWMhCBMEsOZj+KUErfilPv1FL4zP3E8kNCu+B
GYCSuj0doIxreVHDifXd+5Lmhr6NDkhG5QIDAQAB
-----END RSA PUBLIC KEY-----

Does it support the PCKS#8 encoding, which defines the key type within the payload itself? (Note that these are the same - this format includes the Object Identifier as part of the key and omits 'RSA').

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAwEYqf3HAL+h0CbcM6cnVfT6hDw0nNPkLYKld54qRYhJa+txnI8so
bIhP4/1l3TnNZldFFOatRlZAxuNG8Dk4L/QQmDeIsOkYQ5oiytSCbUrJv44aOPjL
G72XhVOaOLMT2vp/guOVAjTYOyF83asoOpPVtFeiBHhKudMrpPzeq3qwGMxfVVPy
NlztFjnTlkAKMtkbkwcpzdTn4y/pDo47+LgkDckReoqTIK4Z1bp86Oa6eBOa7/6w
hIXG3aCQiMQfJUBEBRA7mmV4g+jNWMhCBMEsOZj+KUErfilPv1FL4zP3E8kNCu+B
GYCSuj0doIxreVHDifXd+5Lmhr6NDkhG5QIDAQAB
-----END PUBLIC KEY-----

Error: The first argument must be one of type...

If you pass a random string like 'test' to jws.verify, you get this error. Instead it should just return false.

  TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type undefined
      at Function.from (buffer.js:199:11)
      at Object.verify (....../node_modules/jwa/index.js:43:31)
      at Object.jwsVerify [as verify] (....../node_modules/jws/lib/verify-stream.js:54:15)

issue using RS512

Hello,
whenever I try to use a RSA 512 certificates I'm crashing with the following error:

error:0906D06C:PEM routines:PEM_read_bio:no start line:../deps/openssl/openssl/crypto/pem/pem_lib.c:703:Expecting: ANY PRIVATE KEY

it works fine using a 256 one :(

any suggestion?

Algorithm names should be case-sensitive and uppercase

http://self-issued.info/docs/draft-ietf-jose-json-web-signature.html
Section 4.1.1. "alg" (Algorithm) Header Parameter:
"The alg value is a case-sensitive string containing a StringOrURI value."

The examples provided in readme.md use lowercase algorithm names, and node-jws does not convert them to uppercase, leading to standard-compliant implementations determining them to be invalid JWS signatures.

The list of names in here is all uppercase (except "none") (3.1. "alg" (Algorithm) Header Parameter Values for JWS): http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-26

AWS KMS Support

Hi,
I would like to add support to AWS KMS to jsonwebtoken library.
I was wondering if the play to add this support is in this library.

I have updated other jwt library (https://github.com/fjcabello/jwt-kms) but I would prefer to add this feature in a more standard library.

What do you think?

Thanks,

Paco

Throw an error if a decoded jws signature does not contain an alg field

I recently stumbled upon an issue where if a base64 encoded json object that does not include an alg field is passed to algoFromJWS, the following error will be thrown:

TypeError: Cannot call method 'match' of undefined
    at jwa (/Users/tescherm/stuff/node_modules/jsonwebtoken/node_modules/jws/node_modules/jwa/index.js:91:27)
    at Object.jwsVerify [as verify] (/Users/tescherm/stuff/node_modules/jsonwebtoken/node_modules/jws/index.js:97:16)
    at Object.module.exports.verify (/Users/tescherm/stuff/node_modules/jsonwebtoken/index.js:39:17)

I'm pretty sure the fix involves an existence check on header.alg. If it doesn't exist a more meaningful error can be thrown:

https://github.com/brianloveswords/node-jws/blob/master/index.js#L72

build error while using jsonwebtokens in Angular6

ERROR in ./node_modules/jws/lib/verify-stream.js
Module not found: Error: Can't resolve 'stream' in 'E:\My Code\mycode\pwa\node_modules\jws\lib'
ERROR in ./node_modules/jws/lib/data-stream.js
Module not found: Error: Can't resolve 'stream' in 'E:\My Code\mycode\pwa\node_modules\jws\lib'
ERROR in ./node_modules/jws/lib/sign-stream.js
Module not found: Error: Can't resolve 'stream' in 'E:\My Code\mycode\pwa\node_modules\jws\lib'

siginging with RSA256 result in empty signature

I'm trying to sign with RSA256 with the following:

var jws = require('jws');
var o = jws.sign({
header: {alg: 'RS256', typ: 'JWT'},
payload: payload,
secret: key
});

console.log(o);

the result signature is empty (only header and payload segments, and the token ends with a '.')

ReferenceError: global is not defined

Trying to use the sign function in an Angular application. Have installed jws and @types/jws packages.

This is the reference from my app

sign({
      header: { alg: 'HS256' },
      payload: testuser,
      secret: 'local auth secret'
    });

This is the error stack thrown in the browser console

index.js:43 Uncaught ReferenceError: global is not defined
    at Object.../../node_modules/buffer/index.js (index.js:43)
    at __webpack_require__ (bootstrap:84)
    at Object.../../node_modules/safe-buffer/index.js (index.js:2)
    at __webpack_require__ (bootstrap:84)
    at Object.../../node_modules/jws/lib/sign-stream.js (sign-stream.js:2)
    at __webpack_require__ (bootstrap:84)
    at Object.../../node_modules/jws/index.js (index.js:2)
    at __webpack_require__ (bootstrap:84)
    at Module.../../libs/auth/src/lib/auth-local.service.ts (auth-local.module.ts:10)
    at __webpack_require__ (bootstrap:84)
../../node_modules/buffer/index.js	@	index.js:43
__webpack_require__	@	bootstrap:84
../../node_modules/safe-buffer/index.js	@	index.js:2
__webpack_require__	@	bootstrap:84
../../node_modules/jws/lib/sign-stream.js	@	sign-stream.js:2
__webpack_require__	@	bootstrap:84
../../node_modules/jws/index.js	@	index.js:2
__webpack_require__	@	bootstrap:84
../../libs/auth/src/lib/auth-local.service.ts	@	auth-local.module.ts:10
__webpack_require__	@	bootstrap:84
../../libs/auth/src/lib/auth.service.provider.ts	@	auth.interceptor.ts:13
__webpack_require__	@	bootstrap:84
../../libs/auth/src/index.ts	@	okta-config.ts:10
__webpack_require__	@	bootstrap:84
./src/app/app.module.ts	@	app.component.ts:10
__webpack_require__	@	bootstrap:84
./src/main.ts	@	environment.ts:18
__webpack_require__	@	bootstrap:84
0	@	main.ts:31
__webpack_require__	@	bootstrap:84
checkDeferredModules	@	bootstrap:45
webpackJsonpCallback	@	bootstrap:32
(anonymous)	@	main.js:1

Support for custom sign / verify algorithms

Would you consider accepting an object for the algorithm parameter in jwsVerify, as well checking for the presence of opts.algo in jwsSign? This would involve checking for string vs object to decide whether to use jwa or use it as is.

This way someone could pass {sign: function, verify: function} to support custom algorithms without needing to rewrite this module.

Fix for Issue #50 not released for over two years

Can you make a new release that fixes #50 (PR #52)? The issue has been solved, but unreleased, since Jul 18, 2017...

I just ran into this issue again, trying to sign a compressed payload: https://runkit.com/embed/mnbqn7bakltj

const pako = require('pako');
const jws = require('jws');

//function copy pasted from https://github.com/brianloveswords/node-jws/blob/master/lib/sign-stream.js#L8
function base64url(buf) {
    return buf
        .toString('base64')
        .replace(/=/g, '')
        .replace(/\+/g, '-')
        .replace(/\//g, '_');
}

const payload = Buffer.from(
    pako.deflateRaw('asdfasdfasdfasdf') //returns a Uint8Array
);

//expected: "SyxOSUtEwgA"
console.log(
    base64url(
        payload
    )
);
//actual: "SyxOSUtE77-9AA"
console.log(
    jws.sign({
        header: { alg: 'none' },
        payload,
        encoding: 'utf8'
    }).split('.')[1]
);

SignFinal error

I'm trying to generate a signature with jws.sign and I keep getting an error that seems to be coming from crypto.js.

My node code is as follows:


var jws = require('jws');

function getIdentityToken(userID, nonce) {
// Get Provider, Key ID, and private key from Heroku Environment Variables
        var layerProviderID = process.env.LAYER_PROVIDER_ID;  // looks something like ed47c64a-a74f-11e4-85ff-d2a153003309
        var layerKeyID = process.env.LAYER_KEY_ID;  // looks something like ed47c64a-a74f-11e4-85ff-d2a153003309
        var privateKey = process.env.LAYER_KEY;  MIICWwIBAAKBgQCP/pfcXdzD9f6kK/7cXE+LwvS1fd6JWXDLIxo5wjyjaL9+dMMo6yucGuQRAwORHQpePOtX2vGtRLlS2Cw23YPCpoYa8RLC9CWCOf8yXzj6kz7L5aBZeCZcaWAph0W+939nyprc4H4iAbydOkY1Ydjnnx+CcnXSpMl1GiV6OsbyiwIDAQABAoGARVZtPfocwmgENH3S/b2duEkqmPKBZFYjUE4Y5NM5a96Wx4fmKiAEIel5BRAUeZ4oTfS7xtRxJ+Q98TyTHeBQ/4LAipjs1srgPQUCgs3L1KmflmjdnnGl0KmxZomW9iUxKt6PEoG3sRxWMW3gd84gWJ3twZde1Hp0CYQ4LawzmECQQDPx+gnsLazEyNgZoCLM9zXWQxm2g9cRW0CVk64XQELowaV3Q3Bg94y4IwSyY6kms2gw6OLMHZs9rJ7jgtR0RLJAkEAsWkwfLZmM/AnnPA5ozqelx8VgDQvg13wPfYFz1/qxFA5/QJnmJBLfRnr7imS94Mgla/b4zHtq5iaOPSaFfhQswJAJfgZ7GbWfBLbPBp/EvD/Qjr7kS/37pyhNvQenoIgVsgLxAcJJHu8dv+hmS1L67h+KwqVMDJC8daC9yEV4HWcQQJAbP5J6qSIn6oQPCudzXlrCzjhq5iupcRSaTwbBxQiRi/AZ4CXFDYbAyefN+bCS+PsXXr7+4VK+lIzlYA41fyLXwJAcf30R3VqT757JDSQ8URSyI1IzA016dkxiR86h9p2mBiLMVo2E0V8pLI5KW1vpL8czlTGCzSNsc7Wu49QLej96g==

        if (!layerProviderID || !layerKeyID || !privateKey) {
            res.send(500, { status: 500, message: err.message });
        } 

        var header =  {
      typ: "JWS", 
      alg: "RS256", 
      cty: "layer-eit;v=1", 
      kid: layerKeyID,
    };

    var currentTimeInSeconds = Math.round(new Date() / 1000);
    var expirationTime = currentTimeInSeconds + 10000;

    var payload = JSON.stringify({
      iss: layerProviderID,
      prn: userID,
      iat: currentTimeInSeconds,
      exp: expirationTime,
      nce: nonce,
    });

    var signature = jws.sign({ 
      header: header, 
      payload: payload, 
      secret: privateKey.toString()
    });

    return signature;
};
exports.getIdentityToken = getIdentityToken;

The error I'm getting is:

40735208461056:error:0906D06C:PEM routines:PEM_read_bio:no start line:../deps/openssl/openssl/crypto/pem/pem_lib.c:703:Expecting: ANY PRIVATE KEY
Error: SignFinal error
    at Sign.sign (crypto.js:429:27)
    at Object.sign (/work/dif-api/node_modules/jws/node_modules/jwa/index.js:51:47)
    at Object.jwsSign [as sign] (/work/dif-api/node_modules/jws/index.js:34:26)
    at Object.getIdentityToken (/work/dif-api/lib/layerAuth.js:35:25)
    at /work/dif-api/routes/users.js:118:41
    at Layer.handle [as handle_request] (/work/dif-api/node_modules/express/lib/router/layer.js:82:5)
    at next (/work/dif-api/node_modules/express/lib/router/route.js:100:13)
    at Route.dispatch (/work/dif-api/node_modules/express/lib/router/route.js:81:3)
    at Layer.handle [as handle_request] (/work/dif-api/node_modules/express/lib/router/layer.js:82:5)
    at /work/dif-api/node_modules/express/lib/router/index.js:235:24

Do you see anything wrong with the call to jws.sign()? Or any clues as to why this error is being generated?

Question about timing

Does this library have constant time failures?

Is the computation time the same if it's the first OR last byte of a signature that fails?

Cannot sign with empty string as secret

When secret is falsy, no signing is performed and a misleading error is given:

require("jws").sign({header: {alg: "HS256"}, payload: "data", secret: ""});
// TypeError: secret must be a string or buffer

The equivalent with an empty Buffer works:

require("jws").sign({header: {alg: "HS256"}, payload: "data", secret: Buffer("")});
// 'eyJhbGciOiJIUzI1NiJ9.ZGF0YQ.KTmgoUPBPfznrnLx1xjRnlmzfIKWZV4x9cXIi6_RopQ'

Use a better algorithm than UTF-8 to derive keys from string secrets.

Using UTF8 "string to bytes" to derive the key used for signing is not secure. Even with long secrets, this prevents the derived key to be properly randomized when converted to a byte array for signing. Any binary value is not necessarily a valid UTF-8 character sequence, and given most secrets are ASCII passphrases, the possible value range is even narrower.

A better approach would be to use PBKDF2 as a key derivation mechanism, but this would introduce a breaking change in the library.

Edit:
Right now, the most secure way to use a truly random key is to generate a binary key using a good random number generator, convert it to base64, and use the following code to generate the JWT:

function getSignedJwt(payload) {
    const keyAsBase64String = getKeyFromConfig();
    const key = Buffer.from(keyAsBase64String, "base64");
    return jws.sign({
        header: { alg: "HS256" },
        payload: payload,
        secret: key
    });
}

verifyStream

If the signature is empty in the object passed to this method it fails silently. I think maybe there is an issue with the error not being emitted. It may not being caught here in this test.

Binary payload is ruined by toString()

Despite ostensibly supporting a binary payload, the bytes of the payload are mangled by including a toString() call before encoding the payload (sign-stream.js:12).

var encodedPayload = base64url(toString(payload), encoding);

A Buffer is binary data - it is not supposed to be transformed into a string, as strings are not capable of containing arbitrary binary data. Right now, this defect mangles bytes outside some safe range (ASCII?).

Example code:

let jws = require("jws");
let payload = Buffer.from("TkJyotZe8NFpgdfnmgINqg==", "base64");
let secret = Buffer.from("8NRxgIkVxP8LyyXSL4b1dg==", "base64");

console.log(payload);

let token = jws.sign({
    "header": {
        "alg": "HS256"
    },
    "payload": payload,
    "secret": secret
});

console.log(token);

Expected result:

eyJhbGciOiJIUzI1NiJ9.TkJyotZe8NFpgdfnmgINqg.9XilaLN_sXqWFtlUCdAlGI85PCEbJZSIQpakyAle-vo

Actual result:

eyJhbGciOiJIUzI1NiJ9.TkJy_f1e_f1p_f39_QIN_Q.plu4DeDn9-SUCZvoneyACF3PXMc3F7wvb4P5gGKZagQ

JTI Support

I'd like to see the JTI (JWT ID) claim implemented so that I could, say, keep track of 'active' tokens out in the wild. And like the spec says it could be used to help prevent any replay attacks.

Are there any plans for this?

Fix for security flaw

I saw this was implemented for disallowing arbitrary algorithms to be verified, I guess to prevent the none one to always go through. Though this breaks the spec which says the server should not have prior knowledge of the algorithm.

Would you consider disabling none by default rather than changing the signature of verify()?

PrivateKey Encrypted

Hello,
JWT accept an object like this one:
{key: your key, passphrase: your passphrase}

But with jws no way to use a private key encrypted because we can't add an object..
How can we handle this case ?

Need to specify encoding on decode.

My JWS payload is some raw bytes, which I pass to the encode function as base64, using the supported "base64" encoding option:

jws.sign({
  header: {
    alg: "HS256"
  },
  payload: "myPayloadBase64=",
  secret: "secret",
  encoding: "base64"
})
// 'eyJhbGciOiJIUzI1NiJ9.myPayloadBase64.rFU9W9o-1Mw3jEudDOFjQZHrxOOmMZdTRnLbXTL2VY8'

When I decode this, there's no corresponding option to decode directly to base64. Decode gives me a string using the encoded bytes, but it contains some escaped character values and is not compatible with Buffer:

const decodedPayload = jws.decode('eyJhbGciOiJIUzI1NiJ9.myPayloadBase64.rFU9W9o-1Mw3jEudDOFjQZHrxOOmMZdTRnLbXTL2VY8')
// '�#��Z\u001at\u0016�{�'

Buffer.from(decodedPayload, "utf8").toString("base64")
//'77+9I++/ve+/vVoadBbvv71777+9'
// should be 'myPayloadBase64='

My workaround right now is to not use decode at all. Instead, I just split('.')[1] and then require('base64-url') to decode the bytes or convert it to normal base64.

It would be much easier if I were able to pass the encoding I used to the decode method to get my base64 (or whatever other encoding) directly.

jws.decode(jwsStr, "base64" /* any supported encoding */)
/*
  {
    header: { alg: "HS256" },
    payload: "myPayloadBase64=",
    signature: "rFU9W9o-1Mw3jEudDOFjQZHrxOOmMZdTRnLbXTL2VY8"
  }
*/

As an additional feature suggestion, this would also let people ask decode to automatically parse JSON payloads:

const encoded = jws.sign({header:{alg: "HS256"}, payload: {test: "value"}, secret: "secret"})
jws.decode(encoded, "json")
// {test: 'value'}

Question: implementing the package with react native

Hi,
I don't know if this is the right location because currently I am focusing on the client side, but:
I want to add digital signature to a react native application.
The application receive data in JSON format and should validate that data while the application will hold the public key.

I am using RN version 0.45.1

Thanks,

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.