@fastify/auth
Advanced tools
| 'use strict' | ||
| const Fastify = require('fastify') | ||
| function build (opts) { | ||
| const fastify = Fastify(opts) | ||
| fastify.register(require('@fastify/jwt'), { secret: 'supersecret' }) | ||
| fastify.register(require('@fastify/leveldb'), { name: 'authdb-async' }) | ||
| fastify.register(require('../auth')) | ||
| fastify.register(routes) | ||
| fastify.decorate('verifyJWTandLevel', verifyJWTandLevel) | ||
| fastify.decorate('verifyUserAndPassword', verifyUserAndPassword) | ||
| function verifyJWTandLevel (request, reply) { | ||
| const jwt = this.jwt | ||
| const level = this.level['authdb-async'] | ||
| if (request.body && request.body.failureWithReply) { | ||
| reply.code(401).send({ error: 'Unauthorized' }) | ||
| return Promise.reject(new Error()) | ||
| } | ||
| if (!request.raw.headers.auth) { | ||
| return Promise.reject(new Error('Missing token header')) | ||
| } | ||
| return new Promise(function (resolve, reject) { | ||
| jwt.verify(request.raw.headers.auth, function (err, decoded) { | ||
| if (err) { return reject(err) }; | ||
| resolve(decoded) | ||
| }) | ||
| }).then(function (decoded) { | ||
| return level.get(decoded.user) | ||
| .then(function (password) { | ||
| if (!password || password !== decoded.password) { | ||
| throw new Error('Token not valid') | ||
| } | ||
| }) | ||
| }).catch(function (error) { | ||
| request.log.error(error) | ||
| throw new Error('Token not valid') | ||
| }) | ||
| } | ||
| function verifyUserAndPassword (request, reply, done) { | ||
| const level = this.level['authdb-async'] | ||
| level.get(request.body.user, onUser) | ||
| function onUser (err, password) { | ||
| if (err) { | ||
| if (err.notFound) { | ||
| return done(new Error('Password not valid')) | ||
| } | ||
| return done(err) | ||
| } | ||
| if (!password || password !== request.body.password) { | ||
| return done(new Error('Password not valid')) | ||
| } | ||
| done() | ||
| } | ||
| } | ||
| async function routes (fastify) { | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/register', | ||
| schema: { | ||
| body: { | ||
| type: 'object', | ||
| properties: { | ||
| user: { type: 'string' }, | ||
| password: { type: 'string' } | ||
| }, | ||
| required: ['user', 'password'] | ||
| } | ||
| }, | ||
| handler: (req, reply) => { | ||
| req.log.info('Creating new user') | ||
| fastify.level['authdb-async'].put(req.body.user, req.body.password, onPut) | ||
| function onPut (err) { | ||
| if (err) return reply.send(err) | ||
| fastify.jwt.sign(req.body, onToken) | ||
| } | ||
| function onToken (err, token) { | ||
| if (err) return reply.send(err) | ||
| req.log.info('User created') | ||
| reply.send({ token }) | ||
| } | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'GET', | ||
| url: '/no-auth', | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth free route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'GET', | ||
| url: '/auth', | ||
| preHandler: fastify.auth([fastify.verifyJWTandLevel]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/auth-multiple', | ||
| preHandler: fastify.auth([ | ||
| fastify.verifyJWTandLevel, | ||
| fastify.verifyUserAndPassword | ||
| ]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| } | ||
| return fastify | ||
| } | ||
| if (require.main === module) { | ||
| const fastify = build({ | ||
| logger: { | ||
| level: 'info' | ||
| } | ||
| }) | ||
| fastify.listen({ port: 3000, host: '0.0.0.0' }, err => { | ||
| if (err) throw err | ||
| }) | ||
| } | ||
| module.exports = build |
| 'use strict' | ||
| const Fastify = require('fastify') | ||
| function build (opts) { | ||
| const fastify = Fastify(opts) | ||
| fastify | ||
| .register(require('../auth')) | ||
| .after(routes) | ||
| fastify.decorate('verifyNumber', verifyNumber) | ||
| fastify.decorate('verifyOdd', verifyOdd) | ||
| fastify.decorate('verifyBig', verifyBig) | ||
| function verifyNumber (request, reply, done) { | ||
| const n = request.body.n | ||
| if (typeof (n) !== 'number') { | ||
| request.number = false | ||
| return done(new Error('type of `n` is not `number`')) | ||
| } | ||
| request.number = true | ||
| return done() | ||
| } | ||
| function verifyOdd (request, reply, done) { | ||
| const n = request.body.n | ||
| if (typeof (n) !== 'number' || n % 2 === 0) { | ||
| request.odd = false | ||
| return done(new Error('`n` is not odd')) | ||
| } | ||
| request.odd = true | ||
| return done() | ||
| } | ||
| function verifyBig (request, reply, done) { | ||
| const n = request.body.n | ||
| if (typeof (n) !== 'number' || n < 100) { | ||
| request.big = false | ||
| return done(new Error('`n` is not big')) | ||
| } | ||
| request.big = true | ||
| return done() | ||
| } | ||
| function routes () { | ||
| fastify.route({ | ||
| method: 'GET', | ||
| url: '/', | ||
| handler: (req, reply) => { | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/checkand', | ||
| preHandler: fastify.auth([fastify.verifyNumber, fastify.verifyOdd], { relation: 'and' }), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/checkor', | ||
| preHandler: fastify.auth([fastify.verifyOdd, fastify.verifyBig]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/singleor', | ||
| preHandler: fastify.auth([fastify.verifyOdd]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/singleand', | ||
| preHandler: fastify.auth([fastify.verifyOdd], { relation: 'and' }), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/run-all-or', | ||
| preHandler: fastify.auth([fastify.verifyOdd, fastify.verifyBig, fastify.verifyNumber], { run: 'all' }), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ | ||
| odd: req.odd, | ||
| big: req.big, | ||
| number: req.number | ||
| }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/run-all-and', | ||
| preHandler: fastify.auth([fastify.verifyOdd, fastify.verifyBig, fastify.verifyNumber], { run: 'all', relation: 'and' }), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ | ||
| odd: req.odd, | ||
| big: req.big, | ||
| number: req.number | ||
| }) | ||
| } | ||
| }) | ||
| } | ||
| return fastify | ||
| } | ||
| if (require.main === module) { | ||
| const fastify = build({ | ||
| logger: { | ||
| level: 'info' | ||
| } | ||
| }) | ||
| fastify.listen({ port: 3000, host: '0.0.0.0' }, err => { | ||
| if (err) throw err | ||
| }) | ||
| } | ||
| module.exports = build |
+178
| 'use strict' | ||
| /* | ||
| Register a user: | ||
| curl -i 'http://127.0.0.1:3000/register' -H 'content-type: application/json' --data '{"user": "myuser","password":"mypass"}' | ||
| Will return: | ||
| {"token":"YOUR_JWT_TOKEN"} | ||
| The application then: | ||
| 1. generates a JWT token (from 'supersecret') and adds to the response headers | ||
| 1. inserts user in the leveldb | ||
| Check it's all working by using one or the other auth mechanisms: | ||
| 1. Auth using username and password (you can also use JWT on this endpoint) | ||
| curl 'http://127.0.0.1:3000/auth-multiple' -H 'content-type: application/json' --data '{"user": "myuser","password":"mypass"}' | ||
| {"hello":"world"} | ||
| 1. Auth using JWT token | ||
| curl -i 'http://127.0.0.1:3000/auth' -H 'content-type: application/json' -H "auth: YOUR_JWT_TOKEN" | ||
| */ | ||
| const Fastify = require('fastify') | ||
| function build (opts) { | ||
| const fastify = Fastify(opts) | ||
| fastify.register(require('@fastify/jwt'), { secret: 'supersecret' }) | ||
| fastify.register(require('@fastify/leveldb'), { name: 'authdb' }) | ||
| fastify.register(require('../auth')) // just 'fastify-auth' IRL | ||
| fastify.after(routes) | ||
| fastify.decorate('verifyJWTandLevelDB', verifyJWTandLevelDB) | ||
| fastify.decorate('verifyUserAndPassword', verifyUserAndPassword) | ||
| function verifyJWTandLevelDB (request, reply, done) { | ||
| const jwt = this.jwt | ||
| const level = this.level.authdb | ||
| if (request.body && request.body.failureWithReply) { | ||
| reply.code(401).send({ error: 'Unauthorized' }) | ||
| return done(new Error()) | ||
| } | ||
| if (!request.raw.headers.auth) { | ||
| return done(new Error('Missing token header')) | ||
| } | ||
| jwt.verify(request.raw.headers.auth, onVerify) | ||
| function onVerify (err, decoded) { | ||
| if (err || !decoded.user || !decoded.password) { | ||
| return done(new Error('Token not valid')) | ||
| } | ||
| level.get(decoded.user, onUser) | ||
| function onUser (err, password) { | ||
| if (err) { | ||
| if (err.notFound) { | ||
| return done(new Error('Token not valid')) | ||
| } | ||
| return done(err) | ||
| } | ||
| if (!password || password !== decoded.password) { | ||
| return done(new Error('Token not valid')) | ||
| } | ||
| done() | ||
| } | ||
| } | ||
| } | ||
| function verifyUserAndPassword (request, reply, done) { | ||
| const level = this.level.authdb | ||
| if (!request.body || !request.body.user) { | ||
| return done(new Error('Missing user in request body')) | ||
| } | ||
| level.get(request.body.user, onUser) | ||
| function onUser (err, password) { | ||
| if (err) { | ||
| if (err.notFound) { | ||
| return done(new Error('Password not valid')) | ||
| } | ||
| return done(err) | ||
| } | ||
| if (!password || password !== request.body.password) { | ||
| return done(new Error('Password not valid')) | ||
| } | ||
| done() | ||
| } | ||
| } | ||
| function routes () { | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/register', | ||
| schema: { | ||
| body: { | ||
| type: 'object', | ||
| properties: { | ||
| user: { type: 'string' }, | ||
| password: { type: 'string' } | ||
| }, | ||
| required: ['user', 'password'] | ||
| } | ||
| }, | ||
| handler: (req, reply) => { | ||
| req.log.info('Creating new user') | ||
| fastify.level.authdb.put(req.body.user, req.body.password, onPut) | ||
| function onPut (err) { | ||
| if (err) return reply.send(err) | ||
| fastify.jwt.sign(req.body, onToken) | ||
| } | ||
| function onToken (err, token) { | ||
| if (err) return reply.send(err) | ||
| req.log.info('User created') | ||
| reply.send({ token }) | ||
| } | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'GET', | ||
| url: '/no-auth', | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth free route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'GET', | ||
| url: '/auth', | ||
| preHandler: fastify.auth([fastify.verifyJWTandLevelDB]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/auth-multiple', | ||
| preHandler: fastify.auth([ | ||
| // Only one of these has to pass | ||
| fastify.verifyJWTandLevelDB, | ||
| fastify.verifyUserAndPassword | ||
| ]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| } | ||
| return fastify | ||
| } | ||
| if (require.main === module) { | ||
| const fastify = build({ | ||
| logger: { | ||
| level: 'info' | ||
| } | ||
| }) | ||
| fastify.listen({ port: 3000 }, err => { | ||
| if (err) throw err | ||
| }) | ||
| } | ||
| module.exports = build |
@@ -17,2 +17,3 @@ name: CI | ||
| with: | ||
| license-check: true | ||
| lint: true |
+10
-11
| { | ||
| "name": "@fastify/auth", | ||
| "version": "3.0.2", | ||
| "version": "4.0.0", | ||
| "description": "Run multiple auth functions in Fastify", | ||
@@ -33,17 +33,16 @@ "repository": { | ||
| "devDependencies": { | ||
| "@fastify/jwt": "^6.0.0", | ||
| "@fastify/jwt": "^6.3.2", | ||
| "@fastify/leveldb": "^5.0.1", | ||
| "@fastify/type-provider-json-schema-to-ts": "^1.0.0", | ||
| "@fastify/type-provider-typebox": "^1.0.0", | ||
| "@types/node": "^18.0.0", | ||
| "fastify": "^4.0.0-rc.3", | ||
| "pre-commit": "^1.2.2", | ||
| "@fastify/pre-commit": "^2.0.2", | ||
| "@fastify/type-provider-json-schema-to-ts": "^2.1.1", | ||
| "@fastify/type-provider-typebox": "^2.3.0", | ||
| "@types/node": "^18.7.14", | ||
| "fastify": "^4.5.3", | ||
| "rimraf": "^3.0.2", | ||
| "standard": "^17.0.0", | ||
| "tap": "^16.0.0", | ||
| "tsd": "^0.21.0", | ||
| "typescript": "^4.0.2" | ||
| "tap": "^16.3.0", | ||
| "tsd": "^0.23.0" | ||
| }, | ||
| "dependencies": { | ||
| "fastify-plugin": "^3.0.0", | ||
| "fastify-plugin": "^4.0.0", | ||
| "reusify": "^1.0.4" | ||
@@ -50,0 +49,0 @@ }, |
+3
-3
@@ -8,3 +8,3 @@ # @fastify/auth | ||
| This module does not provide an authentication strategy, but it provides a very fast utility to handle authentication (and multiple strategies) in your routes, without adding overhead. | ||
| Check out a complete example [here](https://github.com/fastify/fastify-auth/blob/master/example.js). | ||
| Check out a complete example [here](test/example.js). | ||
@@ -76,3 +76,3 @@ ## Install | ||
| ``` | ||
| _For more examples, please check [`example-composited.js`](example-composited.js)_ | ||
| _For more examples, please check [`example-composited.js`](test/example-composited.js)_ | ||
@@ -110,3 +110,3 @@ This plugin support `callback` and `Promise` returned by the functions. Note that an `async` function **does not have** to call the `done` parameter, otherwise the route handler to which the auth methods are linked to [might be called multiple times](https://www.fastify.io/docs/latest/Hooks/#respond-to-a-request-from-a-hook): | ||
| Keep in mind that route definition should either be done as [a plugin](https://github.com/fastify/fastify/blob/master/docs/Plugins.md) or within an `.after()` callback. | ||
| For a complete example implementation, see [example.js](example.js). | ||
| For a complete example implementation, see [example.js](test/example.js). | ||
@@ -113,0 +113,0 @@ `@fastify/auth` will run all your authentication methods and your request will continue if at least one succeeds, otherwise it will return an error to the client. |
@@ -6,3 +6,3 @@ 'use strict' | ||
| const rimraf = require('rimraf') | ||
| const build = require('../example-async') | ||
| const build = require('./example-async') | ||
@@ -9,0 +9,0 @@ let fastify = null |
@@ -5,3 +5,3 @@ 'use strict' | ||
| const test = t.test | ||
| const build = require('../example-composited') | ||
| const build = require('./example-composited') | ||
@@ -8,0 +8,0 @@ let fastify = null |
@@ -6,3 +6,3 @@ 'use strict' | ||
| const rimraf = require('rimraf') | ||
| const build = require('../example') | ||
| const build = require('./example') | ||
@@ -9,0 +9,0 @@ let fastify = null |
Sorry, the diff of this file is not supported yet
-146
| 'use strict' | ||
| const Fastify = require('fastify') | ||
| function build (opts) { | ||
| const fastify = Fastify(opts) | ||
| fastify.register(require('@fastify/jwt'), { secret: 'supersecret' }) | ||
| fastify.register(require('@fastify/leveldb'), { name: 'authdb-async' }) | ||
| fastify.register(require('./auth')) | ||
| fastify.register(routes) | ||
| fastify.decorate('verifyJWTandLevel', verifyJWTandLevel) | ||
| fastify.decorate('verifyUserAndPassword', verifyUserAndPassword) | ||
| function verifyJWTandLevel (request, reply) { | ||
| const jwt = this.jwt | ||
| const level = this.level['authdb-async'] | ||
| if (request.body && request.body.failureWithReply) { | ||
| reply.code(401).send({ error: 'Unauthorized' }) | ||
| return Promise.reject(new Error()) | ||
| } | ||
| if (!request.raw.headers.auth) { | ||
| return Promise.reject(new Error('Missing token header')) | ||
| } | ||
| return new Promise(function (resolve, reject) { | ||
| jwt.verify(request.raw.headers.auth, function (err, decoded) { | ||
| if (err) { return reject(err) }; | ||
| resolve(decoded) | ||
| }) | ||
| }).then(function (decoded) { | ||
| return level.get(decoded.user) | ||
| .then(function (password) { | ||
| if (!password || password !== decoded.password) { | ||
| throw new Error('Token not valid') | ||
| } | ||
| }) | ||
| }).catch(function (error) { | ||
| request.log.error(error) | ||
| throw new Error('Token not valid') | ||
| }) | ||
| } | ||
| function verifyUserAndPassword (request, reply, done) { | ||
| const level = this.level['authdb-async'] | ||
| level.get(request.body.user, onUser) | ||
| function onUser (err, password) { | ||
| if (err) { | ||
| if (err.notFound) { | ||
| return done(new Error('Password not valid')) | ||
| } | ||
| return done(err) | ||
| } | ||
| if (!password || password !== request.body.password) { | ||
| return done(new Error('Password not valid')) | ||
| } | ||
| done() | ||
| } | ||
| } | ||
| async function routes (fastify) { | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/register', | ||
| schema: { | ||
| body: { | ||
| type: 'object', | ||
| properties: { | ||
| user: { type: 'string' }, | ||
| password: { type: 'string' } | ||
| }, | ||
| required: ['user', 'password'] | ||
| } | ||
| }, | ||
| handler: (req, reply) => { | ||
| req.log.info('Creating new user') | ||
| fastify.level['authdb-async'].put(req.body.user, req.body.password, onPut) | ||
| function onPut (err) { | ||
| if (err) return reply.send(err) | ||
| fastify.jwt.sign(req.body, onToken) | ||
| } | ||
| function onToken (err, token) { | ||
| if (err) return reply.send(err) | ||
| req.log.info('User created') | ||
| reply.send({ token }) | ||
| } | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'GET', | ||
| url: '/no-auth', | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth free route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'GET', | ||
| url: '/auth', | ||
| preHandler: fastify.auth([fastify.verifyJWTandLevel]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/auth-multiple', | ||
| preHandler: fastify.auth([ | ||
| fastify.verifyJWTandLevel, | ||
| fastify.verifyUserAndPassword | ||
| ]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| } | ||
| return fastify | ||
| } | ||
| if (require.main === module) { | ||
| const fastify = build({ | ||
| logger: { | ||
| level: 'info' | ||
| } | ||
| }) | ||
| fastify.listen({ port: 3000, host: '0.0.0.0' }, err => { | ||
| if (err) throw err | ||
| }) | ||
| } | ||
| module.exports = build |
| 'use strict' | ||
| const Fastify = require('fastify') | ||
| function build (opts) { | ||
| const fastify = Fastify(opts) | ||
| fastify | ||
| .register(require('./auth')) | ||
| .after(routes) | ||
| fastify.decorate('verifyNumber', verifyNumber) | ||
| fastify.decorate('verifyOdd', verifyOdd) | ||
| fastify.decorate('verifyBig', verifyBig) | ||
| function verifyNumber (request, reply, done) { | ||
| const n = request.body.n | ||
| if (typeof (n) !== 'number') { | ||
| request.number = false | ||
| return done(new Error('type of `n` is not `number`')) | ||
| } | ||
| request.number = true | ||
| return done() | ||
| } | ||
| function verifyOdd (request, reply, done) { | ||
| const n = request.body.n | ||
| if (typeof (n) !== 'number' || n % 2 === 0) { | ||
| request.odd = false | ||
| return done(new Error('`n` is not odd')) | ||
| } | ||
| request.odd = true | ||
| return done() | ||
| } | ||
| function verifyBig (request, reply, done) { | ||
| const n = request.body.n | ||
| if (typeof (n) !== 'number' || n < 100) { | ||
| request.big = false | ||
| return done(new Error('`n` is not big')) | ||
| } | ||
| request.big = true | ||
| return done() | ||
| } | ||
| function routes () { | ||
| fastify.route({ | ||
| method: 'GET', | ||
| url: '/', | ||
| handler: (req, reply) => { | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/checkand', | ||
| preHandler: fastify.auth([fastify.verifyNumber, fastify.verifyOdd], { relation: 'and' }), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/checkor', | ||
| preHandler: fastify.auth([fastify.verifyOdd, fastify.verifyBig]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/singleor', | ||
| preHandler: fastify.auth([fastify.verifyOdd]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/singleand', | ||
| preHandler: fastify.auth([fastify.verifyOdd], { relation: 'and' }), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/run-all-or', | ||
| preHandler: fastify.auth([fastify.verifyOdd, fastify.verifyBig, fastify.verifyNumber], { run: 'all' }), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ | ||
| odd: req.odd, | ||
| big: req.big, | ||
| number: req.number | ||
| }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/run-all-and', | ||
| preHandler: fastify.auth([fastify.verifyOdd, fastify.verifyBig, fastify.verifyNumber], { run: 'all', relation: 'and' }), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ | ||
| odd: req.odd, | ||
| big: req.big, | ||
| number: req.number | ||
| }) | ||
| } | ||
| }) | ||
| } | ||
| return fastify | ||
| } | ||
| if (require.main === module) { | ||
| const fastify = build({ | ||
| logger: { | ||
| level: 'info' | ||
| } | ||
| }) | ||
| fastify.listen({ port: 3000, host: '0.0.0.0' }, err => { | ||
| if (err) throw err | ||
| }) | ||
| } | ||
| module.exports = build |
-178
| 'use strict' | ||
| /* | ||
| Register a user: | ||
| curl -i 'http://127.0.0.1:3000/register' -H 'content-type: application/json' --data '{"user": "myuser","password":"mypass"}' | ||
| Will return: | ||
| {"token":"YOUR_JWT_TOKEN"} | ||
| The application then: | ||
| 1. generates a JWT token (from 'supersecret') and adds to the response headers | ||
| 1. inserts user in the leveldb | ||
| Check it's all working by using one or the other auth mechanisms: | ||
| 1. Auth using username and password (you can also use JWT on this endpoint) | ||
| curl 'http://127.0.0.1:3000/auth-multiple' -H 'content-type: application/json' --data '{"user": "myuser","password":"mypass"}' | ||
| {"hello":"world"} | ||
| 1. Auth using JWT token | ||
| curl -i 'http://127.0.0.1:3000/auth' -H 'content-type: application/json' -H "auth: YOUR_JWT_TOKEN" | ||
| */ | ||
| const Fastify = require('fastify') | ||
| function build (opts) { | ||
| const fastify = Fastify(opts) | ||
| fastify.register(require('@fastify/jwt'), { secret: 'supersecret' }) | ||
| fastify.register(require('@fastify/leveldb'), { name: 'authdb' }) | ||
| fastify.register(require('./auth')) // just 'fastify-auth' IRL | ||
| fastify.after(routes) | ||
| fastify.decorate('verifyJWTandLevelDB', verifyJWTandLevelDB) | ||
| fastify.decorate('verifyUserAndPassword', verifyUserAndPassword) | ||
| function verifyJWTandLevelDB (request, reply, done) { | ||
| const jwt = this.jwt | ||
| const level = this.level.authdb | ||
| if (request.body && request.body.failureWithReply) { | ||
| reply.code(401).send({ error: 'Unauthorized' }) | ||
| return done(new Error()) | ||
| } | ||
| if (!request.raw.headers.auth) { | ||
| return done(new Error('Missing token header')) | ||
| } | ||
| jwt.verify(request.raw.headers.auth, onVerify) | ||
| function onVerify (err, decoded) { | ||
| if (err || !decoded.user || !decoded.password) { | ||
| return done(new Error('Token not valid')) | ||
| } | ||
| level.get(decoded.user, onUser) | ||
| function onUser (err, password) { | ||
| if (err) { | ||
| if (err.notFound) { | ||
| return done(new Error('Token not valid')) | ||
| } | ||
| return done(err) | ||
| } | ||
| if (!password || password !== decoded.password) { | ||
| return done(new Error('Token not valid')) | ||
| } | ||
| done() | ||
| } | ||
| } | ||
| } | ||
| function verifyUserAndPassword (request, reply, done) { | ||
| const level = this.level.authdb | ||
| if (!request.body || !request.body.user) { | ||
| return done(new Error('Missing user in request body')) | ||
| } | ||
| level.get(request.body.user, onUser) | ||
| function onUser (err, password) { | ||
| if (err) { | ||
| if (err.notFound) { | ||
| return done(new Error('Password not valid')) | ||
| } | ||
| return done(err) | ||
| } | ||
| if (!password || password !== request.body.password) { | ||
| return done(new Error('Password not valid')) | ||
| } | ||
| done() | ||
| } | ||
| } | ||
| function routes () { | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/register', | ||
| schema: { | ||
| body: { | ||
| type: 'object', | ||
| properties: { | ||
| user: { type: 'string' }, | ||
| password: { type: 'string' } | ||
| }, | ||
| required: ['user', 'password'] | ||
| } | ||
| }, | ||
| handler: (req, reply) => { | ||
| req.log.info('Creating new user') | ||
| fastify.level.authdb.put(req.body.user, req.body.password, onPut) | ||
| function onPut (err) { | ||
| if (err) return reply.send(err) | ||
| fastify.jwt.sign(req.body, onToken) | ||
| } | ||
| function onToken (err, token) { | ||
| if (err) return reply.send(err) | ||
| req.log.info('User created') | ||
| reply.send({ token }) | ||
| } | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'GET', | ||
| url: '/no-auth', | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth free route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'GET', | ||
| url: '/auth', | ||
| preHandler: fastify.auth([fastify.verifyJWTandLevelDB]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| fastify.route({ | ||
| method: 'POST', | ||
| url: '/auth-multiple', | ||
| preHandler: fastify.auth([ | ||
| // Only one of these has to pass | ||
| fastify.verifyJWTandLevelDB, | ||
| fastify.verifyUserAndPassword | ||
| ]), | ||
| handler: (req, reply) => { | ||
| req.log.info('Auth route') | ||
| reply.send({ hello: 'world' }) | ||
| } | ||
| }) | ||
| } | ||
| return fastify | ||
| } | ||
| if (require.main === module) { | ||
| const fastify = build({ | ||
| logger: { | ||
| level: 'info' | ||
| } | ||
| }) | ||
| fastify.listen({ port: 3000 }, err => { | ||
| if (err) throw err | ||
| }) | ||
| } | ||
| module.exports = build |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
11
-8.33%47686
-0.12%16
-5.88%1
Infinity%+ Added
- Removed
Updated