Skip to content

Commit

Permalink
add support to set optional reserved headers
Browse files Browse the repository at this point in the history
  • Loading branch information
joaquimserafim committed Jan 23, 2017
1 parent 1210ff3 commit 7a83804
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 52 deletions.
40 changes: 33 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ the version `2.*.*` should work only for NodeJS >= **4** for NodeJS **0.10** and
##### jwt#encode(key, payload, [algorithm], cb)

* **key**, your secret
* **payload**, the payload or Claim Names,
* **payload**, the payload or Claim Names or an object with {payload, header}

*ex:*
```js
Expand All @@ -49,7 +49,7 @@ the version `2.*.*` should work only for NodeJS >= **4** for NodeJS **0.10** and

* **key**, your secret
* **token**, the JWT token
* **cb**, the callback(err[name, message], payloadDecoded)
* **cb**, the callback(err[name, message], decodedPayload[, decodedHeader])


#### Example
Expand All @@ -74,25 +74,51 @@ var secret = 'TOPSECRETTTTT';
// encode
jwt.encode(secret, payload, function (err, token) {
if (err) {
return console.error(err.name, err.message);
console.error(err.name, err.message);
} else {
console.log(token);

// decode
jwt.decode(secret, token, function (err_, decode) {
jwt.decode(secret, token, function (err_, decodedPayload, decodedHeader) {
if (err) {
return console.error(err.name, err.message);
console.error(err.name, err.message);
} else {
console.log(decode);
console.log(decodedPayload, decodedHeader);
}
});
}
});
```

**using the optional [reserved headers](http://self-issued.info/docs/draft-jones-json-web-token-01.html#ReservedHeaderParameterName) (alg and typ can't be set using this method)**
```js
var settingAddHeaders = {
payload: {
"iss": "my_issurer",
"aud": "World",
"iat": 1400062400223,
"typ": "/online/transactionstatus/v2",
"request": {
"myTransactionId": "[myTransactionId]",
"merchantTransactionId": "[merchantTransactionId]",
"status": "SUCCESS"
}
},
header: {
kid: 'key ID'
}
}

jwt.encode(secret, settingAddHeaders, function (err, token) {

})

```


---

#####this projet has been set up with a precommit that forces you to follow a code style, no jshint issues and 100% of code coverage before commit
#### this projet has been set up with a precommit that forces you to follow a code style, no jshint issues and 100% of code coverage before commit

to run test
```js
Expand Down
52 changes: 33 additions & 19 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
'use strict'

var xtend = require('xtend')

const crypto = require('crypto')
const b64url = require('base64-url')
const inherits = require('util').inherits
const parse = require('json-parse-safe')
const extend = require('xtend')
const isObject = require('is.object')

//
// supported algorithms
Expand Down Expand Up @@ -33,22 +33,29 @@ function getAlgorithms () {
return Object.keys(algorithms)
}

function encode (key, payload, algorithm, cb) {
function encode (key, data, algorithm, cb) {
if (paramIsValid(algorithm, 'function')) {
cb = algorithm
algorithm = 'HS256'
}

var validationError = encodeValidations(key, payload, algorithm)
var defaultHeader = {typ: 'JWT', alg: algorithm}

var payload = isObject(data) && data.payload ?
data.payload :
data

var header = isObject(data) && data.header ?
extend(data.header, defaultHeader) :
defaultHeader

const validationError = encodeValidations(key, payload, algorithm)

if (validationError) {
return prcResult(validationError, null, cb)
}

var header = xtend({typ: 'JWT', alg: algorithm}, payload.header);
delete payload.header;

var parts = b64url.encode(JSON.stringify(header)) +
const parts = b64url.encode(JSON.stringify(header)) +
'.' +
b64url.encode(JSON.stringify(payload))

Expand All @@ -64,7 +71,7 @@ function decode (key, token, cb) {
return prcResult('The key and token are mandatory!', null, cb)
}

var parts = token.split('.')
const parts = token.split('.')

// check all parts're present
if (parts.length !== 3) {
Expand All @@ -76,25 +83,25 @@ function decode (key, token, cb) {
}

// base64 decode and parse JSON
var header = JSONParse(b64url.decode(parts[0]))
var payload = JSONParse(b64url.decode(parts[1]))
const header = JSONParse(b64url.decode(parts[0]))
const payload = JSONParse(b64url.decode(parts[1]))

// get algorithm hash and type and check if is valid
var algorithm = algorithms[header.alg]
const algorithm = algorithms[header.alg]

if (!algorithm) {
return prcResult('The algorithm is not supported!', null, cb)
}

// verify the signature
var res = verify(
const res = verify(
algorithm,
key,
parts.slice(0, 2).join('.'),
parts[2]
)

return prcResult(!res && 'Invalid key!' || null, payload, cb)
return prcResult(!res && 'Invalid key!' || null, payload, header, cb)
}

function encodeValidations (key, payload, algorithm) {
Expand Down Expand Up @@ -140,12 +147,20 @@ function verify (alg, key, input, signVar) {
.verify(key, b64url.unescape(signVar), 'base64')
}

function prcResult (err, res, cb) {
function prcResult (err, payload, header, cb) {
if (paramIsValid(header, 'function')) {
cb = header
header = undefined
}

err = err && new JWTError(err)

return cb ?
cb(err, res) :
{error: err, value: res}
cb(err, payload, header) :
(header ?
{error: err, value: payload, header: header} :
{error: err, value: payload}
)
}

function paramIsValid (param, type) {
Expand All @@ -157,8 +172,7 @@ function paramsAreFalsy (param1, param2) {
}

function JSONParse (str) {
var res = parse(str)
const res = parse(str)

return res.error && '' || res.value
}

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "json-web-token",
"version": "2.0.3",
"version": "2.1.3",
"description": "JSON Web Token (JWT) is a compact token format intended for space constrained environments such as HTTP Authorization headers and URI query parameters.",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -39,11 +39,12 @@
"homepage": "https://github.com/joaquimserafim/json-web-token",
"dependencies": {
"base64-url": "^1.2.2",
"is.object": "^1.0.0",
"json-parse-safe": "^1.0.3",
"xtend": "^4.0.1"
},
"devDependencies": {
"istanbul": "^0.4.3",
"istanbul": "0.4.3",
"jscs": "^2.11.0",
"jshint": "^2.9.2",
"nsp": "^2.4.0",
Expand Down
47 changes: 23 additions & 24 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,21 @@
var read = require('fs').readFileSync
var test = require('tape')
var b64url = require('base64-url')

var jwt = require('../.')
var xtend = require('xtend')

var payload = {
iss: 'my_issurer',
aud: 'World',
iat: 1400062400223,
typ: '/online/transactionstatus/v2',
header: {
kid: 'TestKeyId'
},
request: {
myTransactionId: '[myTransactionId]',
merchantTransactionId: '[merchantTransactionId]',
status: 'SUCCESS'
}
}

var extraHeaders = {
header: {kid: 'TestKeyId'}
};

var payloadWithHeaders = xtend(payload, extraHeaders);

var secret = 'TOPSECRETTTTT'
var theToken = null
var theTokenSign = null
Expand Down Expand Up @@ -68,17 +59,6 @@ test('jwt - encode with callback / sign', function(assert) {
})
})

test('jwt + custom headers - encode with callback / sign', function(assert) {
var pem = read(__dirname + '/fixtures/test.pem').toString('ascii')
jwt.encode(pem, payloadWithHeaders, 'RS256', function(err, token) {
assert.deepEqual(err, null)
assert.ok(token)
theTokenSignWithHeaders = token
assert.deepEqual(token.split('.').length, 3)
assert.end()
})
})

test('jwt - encode with callback / bad algorithm', function(assert) {
jwt.encode(secret, payload, 'wow', function(err) {
assert.deepEqual(err.message, 'The algorithm is not supported!')
Expand All @@ -103,11 +83,30 @@ test('jwt - decode with callback / sign', function(assert) {
})
})

test('jwt + custom headers - encode with callback / sign', function(assert) {
var pem = read(__dirname + '/fixtures/test.pem').toString('ascii')
var payloadAndHeaders = {
payload: payload,
header: {
kid: 'TestKeyId'
}
}

jwt.encode(pem, payloadAndHeaders, 'RS256', function(err, token) {
assert.deepEqual(err, null)
assert.ok(token)
theTokenSignWithHeaders = token
assert.deepEqual(token.split('.').length, 3)
assert.end()
})
})

test('jwt + custom headers - decode with callback / sign', function(assert) {
var crt = read(__dirname + '/fixtures/test.crt').toString('ascii')
jwt.decode(crt, theTokenSignWithHeaders, function(err, decodePayload) {
jwt.decode(crt, theTokenSignWithHeaders, function(err, decPayload, header) {
assert.deepEqual(err, null)
assert.deepEqual(decodePayload, payloadWithHeaders)
assert.deepEqual(decPayload, payload)
assert.deepEqual(header.kid, 'TestKeyId')
assert.end()
})
})
Expand Down Expand Up @@ -184,6 +183,7 @@ test('jwt - decode with callback / bad token', function(assert) {
//
// without callback but returning the result
//

test('jwt - encode without callback / hmac', function(assert) {
var res = jwt.encode(secret, payload)
assert.deepEqual(typeof res, 'object')
Expand Down Expand Up @@ -250,4 +250,3 @@ test('should not decode for the "none" algorithm', function(assert) {
assert.equal(result.error.message, 'The algorithm is not supported!')
assert.end()
})

0 comments on commit 7a83804

Please sign in to comment.