Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fastify-jwt

Package Overview
Dependencies
Maintainers
6
Versions
48
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fastify-jwt - npm Package Compare versions

Comparing version 0.1.1 to 0.2.0

104

jwt.js
'use strict'
const fp = require('fastify-plugin')
const JWT = require('jsonwebtoken')
const assert = require('assert')
var fp = require('fastify-plugin')
var JWT = require('jsonwebtoken')
var assert = require('assert')
var steed = require('steed')
function fastifyJWT (fastify, opts, next) {
if (!opts.secret) {
function wrapStaticSecretInCallback (secret) {
return function (request, payload, cb) {
return cb(null, secret)
}
}
function fastifyJwt (fastify, options, next) {
if (!options.secret) {
return next(new Error('missing secret'))
}
const secret = opts.secret
var secret = options.secret
var secretCallback = secret
if (typeof secretCallback !== 'function') { secretCallback = wrapStaticSecretInCallback(secretCallback) }
fastify.decorate('jwt', {
decode: decode,
sign: sign,
verify: verify,
decode: decode,
secret: secret
secret: options.secret
})
fastify.decorateReply('jwtSign', replySign)
fastify.decorateRequest('jwtVerify', requestVerify)
next()

@@ -59,4 +72,77 @@

}
function replySign (payload, options, next) {
if (typeof options === 'function') {
next = options
options = {}
} // support no options
var reply = this
if (next === undefined) {
return new Promise(function (resolve, reject) {
reply.jwtSign(payload, options, function (err, val) {
err ? reject(err) : resolve(val)
})
})
}
if (!payload) {
return next(new Error('jwtSign requires a payload'))
}
steed.waterfall([
function getSecret (callback) {
secretCallback(reply.request, payload, callback)
},
function sign (secret, callback) {
JWT.sign(payload, secret, options, callback)
}
], next)
} // end sign
function requestVerify (options, next) {
if (typeof options === 'function') {
next = options
options = {}
} // support no options
var request = this
if (next === undefined) {
return new Promise(function (resolve, reject) {
request.jwtVerify(options, function (err, val) {
err ? reject(err) : resolve(val)
})
})
}
var token
if (request.headers && request.headers.authorization) {
var parts = request.headers.authorization.split(' ')
if (parts.length === 2) {
var scheme = parts[0]
token = parts[1]
if (!/^Bearer$/i.test(scheme)) {
return next(new Error('Format is Authorization: Bearer [token]'))
}
}
} else {
return next(new Error('No Authorization was found in request.headers'))
}
var decodedToken = JWT.decode(token, options)
steed.waterfall([
function getSecret (callback) {
secretCallback(request, decodedToken, callback)
},
function verify (secret, callback) {
JWT.verify(token, secret, options, callback)
}
], function (err, result) {
if (err) next(err)
request.user = result
next(null, result)
})
} // end verify
}
module.exports = fp(fastifyJWT, '>=0.13.1')
module.exports = fp(fastifyJwt, '>= 0.39')

13

package.json
{
"name": "fastify-jwt",
"version": "0.1.1",
"version": "0.2.0",
"description": "JWT utils for Fastify",

@@ -27,10 +27,13 @@ "main": "jwt.js",

"dependencies": {
"fastify-plugin": "^0.1.1",
"jsonwebtoken": "^8.1.0"
"fastify-plugin": "^0.2.1",
"jsonwebtoken": "^8.1.0",
"steed": "^1.1.3"
},
"devDependencies": {
"fastify": "^0.30.2",
"fastify": "^0.39",
"request": "^2.83.0",
"request-promise-native": "^1.0.5",
"standard": "^10.0.3",
"tap": "^10.7.2"
"tap": "^11.0.1"
}
}

@@ -13,9 +13,8 @@ # fastify-jwt

## Usage
Register it as plugin and then access it via `jwt`.
The api is the same of [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken), refer to their documentation to find how use the utilities.
Register as a plugin. This will decorate your `fastify` instance with the standard [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) methods `decode`, `sign`, and `verify`; refer to their documentation to find how to use the utilities. It will also register `request.jwtVerify` and `reply.jwtSign`. You must pass a `secret` when registering the plugin.
```js
const fastify = require('fastify')
fastify.register(require('fastify-jwt'), { secret: 'supersecret' }, err => {
if (err) throw err
fastify.register(require('fastify-jwt'), {
secret: 'supersecret'
})

@@ -34,2 +33,115 @@

## API Spec
### fastify-jwt
`fastify-jwt` is a fastify plugin. You must pass a `secret` to the `options` parameter. The `secret` can be a primitive type String or a function that returns a String. Function based `secret` is supported by the `request.jwtVerify()` and `reply.jwtSign()` methods and is called with `request`, `reply`, and `callback` parameters.
#### Example
```js
const fastify = require('fastify')()
const jwt = require('fastify-jwt')
// secret as a string
fastify.register(jwt, { secret: 'supersecret' })
// secret as a function
fastify.register(jwt, {
secret: function (request, reply, callback) {
// do something
callback(null, 'supersecret')
}
})
```
### fastify.jwt.sign(payload [,options] [,callback])
The `sign` method is an implementation of [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken#jwtsignpayload-secretorprivatekey-options-callback) `.sign()`. Can be used asynchronously by passing a callback function; synchronously without a callback.
### fastify.jwt.verify(token, [,options] [,callback])
The `verify` method is an implementation of [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken#jwtverifytoken-secretorpublickey-options-callback) `.verify()`. Can be used asynchronously by passing a callback function; synchronously without a callback.
#### Example
```js
const token = fastify.jwt.sign({ foo: 'bar' })
// synchronously
const decoded = fastify.jwt.verify(token)
// asycnhronously
fastify.jwt.verify(token, (err, decoded) => {
if (err) fastify.log.error(err)
fastify.log.info(`Token verified. Foo is ${decoded.foo}`)
})
```
### fastify.jwt.decode(token [,options])
The `decode` method is an implementation of [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken#jwtdecodetoken--options) `.decode()`. Can only be used synchronously.
#### Example
```js
const token = fastify.jwt.sign({ foo: 'bar' })
const decoded = fastify.jwt.decode(token)
fastify.log.info(`Decoded JWT: ${decoded}`)
```
### fastify.jwt.secret
For your convenience, the `secret` you specify during `.register` is made available via `fastify.jwt.secret`. `request.jwtVerify()` and `reply.jwtSign()` will wrap non-function secrets in a callback function. `request.jwtVerify()` and `reply.jwtSign()` use an asynchronous waterfall method to retrieve your secret. It's recommended that your use these methods if your `secret` method is asynchronous.
### reply.jwtSign(payload, [options,] callback)
### request.jwtVerify([options,] callback)
These methods are very similar to their standard jsonwebtoken counterparts.
#### Example
```js
const fastify = require('fastify')()
fastify.register(jwt, {
secret: function (request, reply, callback) {
// do something
callback(null, 'supersecret')
}
})
fastify.post('/sign', function (request, reply) {
reply.jwtSign(request.body.payload, function (err, token) {
return reply.send(err || { 'token': token })
})
})
fastify.get('/verify', function (request, reply) {
request.jwtVerify(function (err, decoded) {
return reply.send(err || decoded)
})
})
fastify.listen(3000, function (err) {
if (err) fastify.log.error(err)
fastify.log.info(`Server live on port: ${fastify.server.address().port}`)
// sign payload and get JWT
request({
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: {
payload: {
foo: 'bar'
}
},
uri: `http://localhost:${fastify.server.address().port}/sign`,
json: true
}, function (err, response, body) {
if (err) fastify.log.error(err)
fastify.log.info(`JWT token is ${body}`)
// verify JWT
request({
method: 'GET',
headers: {
'Content-Type': 'application/json',
authorization: 'Bearer ' + sign.token
},
uri: 'http://localhost:' + fastify.server.address().port + '/verify',
json: true
}, function (err, response, body) {
if (err) fastify.log.error(err)
fastify.log.info(`JWT verified. Foo is ${body.bar}`)
})
})
})
```
## Acknowledgements

@@ -36,0 +148,0 @@

'use strict'
const test = require('tap').test
const Fastify = require('fastify')
const jwt = require('./jwt')
var test = require('tap').test
var Fastify = require('fastify')
var rp = require('request-promise-native')
var jwt = require('./jwt')
test('fastify-jwt should expose jwt methods', t => {
t.plan(5)
const fastify = Fastify()
test('fastify-jwt should expose jwt methods', function (t) {
t.plan(8)
var fastify = Fastify()
fastify
.register(jwt, { secret: 'supersecret' }, t.error)
.after(() => {
.register(jwt, { secret: 'supersecret' })
.ready(function () {
t.ok(fastify.jwt.decode)
t.ok(fastify.jwt.sign)
t.ok(fastify.jwt.verify)
t.ok(fastify.jwt.decode)
t.ok(fastify.jwt.secret)
})
fastify.get('/test', function (request, reply) {
t.ok(request.jwtVerify)
t.ok(reply.jwtSign)
reply.send({ foo: 'bar' })
})
fastify.listen(0, function (err) {
fastify.server.unref()
t.error(err)
rp({
method: 'GET',
uri: 'http://localhost:' + fastify.server.address().port + '/test',
json: true
}).then(function (response) {
t.ok(response)
}).catch(function (err) {
t.fail(err)
})
})
})
test('jwt.secret should be the same as the one given as option', t => {
t.plan(2)
const fastify = Fastify()
test('fastify-jwt fails without secret', function (t) {
t.plan(1)
var fastify = Fastify()
fastify
.register(jwt, { secret: 'supersecret' }, t.error)
.after(() => {
t.is(fastify.jwt.secret, 'supersecret')
.register(jwt)
.listen(0, function (err) {
t.is(err.message, 'missing secret')
})
})
test('sync sign and verify', t => {
t.plan(3)
const fastify = Fastify()
fastify
.register(jwt, { secret: 'supersecret' }, t.error)
.after(() => {
const token = fastify.jwt.sign({ hello: 'world' })
t.ok(token)
t.equal(fastify.jwt.verify(token).hello, 'world')
test('sign and verify', function (t) {
t.plan(8)
var fastify = Fastify()
fastify.register(jwt, { secret: 'supersecret' })
fastify.post('/signCallback', function (request, reply) {
reply.jwtSign(request.body.payload, function (err, token) {
return reply.send(err || { 'token': token })
})
})
})
test('async sign and verify', t => {
t.plan(5)
const fastify = Fastify()
fastify
.register(jwt, { secret: 'supersecret' }, t.error)
.after(() => {
fastify.jwt.sign({ hello: 'world' }, (err, token) => {
fastify.get('/verifyCallback', function (request, reply) {
request.jwtVerify(function (err, decoded) {
return reply.send(err || decoded)
})
})
fastify.post('/signPromise', function (request, reply) {
reply.jwtSign(request.body.payload).then(
function (token) {
return reply.send({ 'token': token })
}).catch(function (err) {
return reply.send(err)
})
})
fastify.get('/verifyPromise', function (request, reply) {
request.jwtVerify().then(function (decoded) {
return reply.send(decoded)
}).catch(function (err) {
return reply.send(err)
})
})
fastify.listen(0, function (err) {
fastify.server.unref()
t.error(err)
})
t.test('syncronously', function (t) {
t.plan(1)
fastify.ready(function () {
var token = fastify.jwt.sign({ foo: 'bar' })
var decoded = fastify.jwt.verify(token)
t.is(decoded.foo, 'bar')
})
})
t.test('asynchronously', function (t) {
t.plan(5)
fastify.ready(function () {
fastify.jwt.sign({ foo: 'bar' }, function (err, token) {
t.error(err)
t.ok(token)
fastify.jwt.verify(token, (err, payload) => {
fastify.jwt.verify(token, function (err, decoded) {
t.error(err)
t.equal(payload.hello, 'world')
t.ok(decoded)
t.is(decoded.foo, 'bar')
})
})
})
})
t.test('jwtSign and jwtVerify with callbacks', function (t) {
t.plan(2)
rp({
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: {
payload: {
foo: 'bar'
}
},
uri: 'http://localhost:' + fastify.server.address().port + '/signCallback',
json: true
}).then(function (sign) {
rp({
method: 'GET',
headers: {
'Content-Type': 'application/json',
authorization: 'Bearer ' + sign.token
},
uri: 'http://localhost:' + fastify.server.address().port + '/verifyCallback',
json: true
}).then(function (verify) {
t.ok(verify)
t.is(verify.foo, 'bar')
}).catch(function (err) {
t.fail(err.message)
})
}).catch(function (err) {
t.fail(err.message)
})
})
t.test('jwtSign and jwtVerify without callbacks', function (t) {
t.plan(2)
rp({
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: {
payload: {
foo: 'bar'
}
},
uri: 'http://localhost:' + fastify.server.address().port + '/signPromise',
json: true
}).then(function (sign) {
rp({
method: 'GET',
headers: {
'Content-Type': 'application/json',
authorization: 'Bearer ' + sign.token
},
uri: 'http://localhost:' + fastify.server.address().port + '/verifyPromise',
json: true
}).then(function (verify) {
t.ok(verify)
t.is(verify.foo, 'bar')
}).catch(function (err) {
t.fail(err.message)
})
}).catch(function (err) {
t.fail(err.message)
})
})
t.test('jwtVerify throws No Authorization error', function (t) {
t.plan(1)
rp({
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
uri: 'http://localhost:' + fastify.server.address().port + '/verifyCallback',
json: true
}).then(function () {
t.fail()
}).catch(function (err) {
t.is(err.error.message, 'No Authorization was found in request.headers')
})
})
t.test('jwtVerify throws Authorization Format error', function (t) {
t.plan(1)
rp({
method: 'GET',
headers: {
'Content-Type': 'application/json',
authorization: 'Invalid TokenFormat'
},
uri: 'http://localhost:' + fastify.server.address().port + '/verifyCallback',
json: true
}).then(function () {
t.fail()
}).catch(function (err) {
t.is(err.error.message, 'Format is Authorization: Bearer [token]')
})
})
t.test('jwtSign throws payload error', function (t) {
t.plan(1)
rp({
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
notAPayload: 'sorry'
}),
uri: 'http://localhost:' + fastify.server.address().port + '/signCallback',
json: true
}).then(function () {
t.fail()
}).catch(function (err) {
t.is(err.error.message, 'jwtSign requires a payload')
})
})
})
test('should throw if no secret is given as option', t => {
test('decode', function (t) {
t.plan(1)
const fastify = Fastify()
fastify.register(jwt, err => {
t.is(err.message, 'missing secret')
var fastify = Fastify()
fastify.register(jwt, { secret: 'shh' }).ready(function () {
var token = fastify.jwt.sign({ foo: 'bar' })
var decoded = fastify.jwt.decode(token)
t.is(decoded.foo, 'bar')
})
})
test('sign should throw if the payload is missing', t => {
t.plan(2)
const fastify = Fastify()
test('secret as a function', function (t) {
t.plan(4)
var fastify = Fastify()
fastify
.register(jwt, { secret: 'supersecret' }, t.error)
.after(() => {
try {
fastify.jwt.sign()
t.fail()
} catch (err) {
t.is(err.message, 'missing payload')
.register(jwt, {
secret: function (request, reply, callback) {
callback(null, 'supersecret')
}
})
})
test('verify should throw if the token is missing', t => {
t.plan(2)
const fastify = Fastify()
fastify
.register(jwt, { secret: 'supersecret' }, t.error)
.after(() => {
try {
fastify.jwt.verify()
t.fail()
} catch (err) {
t.is(err.message, 'missing token')
}
fastify.post('/sign', function (request, reply) {
reply.jwtSign(request.body.payload, function (err, token) {
if (err) { return reply.send(err) }
return reply.send({token})
})
})
fastify.get('/verify', function (request, reply) {
request.jwtVerify(function (err, decoded) {
if (err) { return reply.send(err) }
return reply.send(decoded)
})
})
fastify.listen(0, function (err) {
fastify.server.unref()
t.error(err)
rp({
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: {
payload: {
foo: 'bar'
}
},
uri: 'http://localhost:' + fastify.server.address().port + '/sign',
json: true
}).then(function (sign) {
t.ok(sign)
rp({
method: 'GET',
headers: {
'Content-Type': 'application/json',
authorization: 'Bearer ' + sign.token
},
uri: 'http://localhost:' + fastify.server.address().port + '/verify',
json: true
}).then(function (verify) {
t.ok(verify)
t.is(verify.foo, 'bar')
}).catch(function (err) {
t.fail(err)
})
}).catch(function (err) {
t.fail(err)
})
})
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc