Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support to set optional reserved headers with the encode method #13

Merged
merged 1 commit into from
Jan 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
})