You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
5.8 KiB

3 years ago
# fastify-auth
![CI](https://github.com/fastify/fastify-auth/workflows/CI/badge.svg)
[![NPM version](https://img.shields.io/npm/v/fastify-auth.svg?style=flat)](https://www.npmjs.com/package/fastify-auth)
[![Known Vulnerabilities](https://snyk.io/test/github/fastify/fastify-auth/badge.svg)](https://snyk.io/test/github/fastify/fastify-auth)
[![Coverage Status](https://coveralls.io/repos/github/fastify/fastify-auth/badge.svg?branch=master)](https://coveralls.io/github/fastify/fastify-auth?branch=master)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)
This module does not provide an authentication strategy, but it provides a very fast utility to handle authentication (also multiple strategies) in your routes, without adding overhead.
Check out the complete example [here](https://github.com/fastify/fastify-auth/blob/master/example.js).
## Install
```
npm i fastify-auth
```
## Usage
As said above, `fastify-auth` does not provide an authentication strategy, so you must provide authentication by yourself, with a decorator or another plugin.
In the following example, you will find a very simple implementation that should help you understand how to use this module:
```js
fastify
.decorate('verifyJWTandLevel', function (request, reply, done) {
// your validation logic
done() // pass an error if the authentication fails
})
.decorate('verifyUserAndPassword', function (request, reply, done) {
// your validation logic
done() // pass an error if the authentication fails
})
.register(require('fastify-auth'))
.after(() => {
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' })
}
})
})
```
The default relationship of these customized authentication is `or`, while we could also use `and`:
```js
fastify
.decorate('verifyAdmin', function (request, reply, done) {
// your validation logic
done() // pass an error if the authentication fails
})
.decorate('verifyReputation', function (request, reply, done) {
// your validation logic
done() // pass an error if the authentication fails
})
.register(require('fastify-auth'))
.after(() => {
fastify.route({
method: 'POST',
url: '/auth-multiple',
preHandler: fastify.auth([
fastify.verifyAdmin,
fastify.verifyReputation
], {
relation: 'and'
}),
handler: (req, reply) => {
req.log.info('Auth route')
reply.send({ hello: 'world' })
}
})
})
```
_For more examples, please check `example-composited.js`_
This plugin support `callback` and `Promise` returned by the functions. Note that an `async` function does not have to use the `done` parameter:
```js
fastify
.decorate('asyncVerifyJWTandLevel', async function (request, reply) {
// your async validation logic
await validation()
// throws an error if the authentication fails
})
.decorate('asyncVerifyUserAndPassword', function (request, reply) {
// return a promise that throws an error if the authentication fails
return myPromiseValidation()
})
.register(require('fastify-auth'))
.after(() => {
fastify.route({
method: 'POST',
url: '/auth-multiple',
preHandler: fastify.auth([
fastify.asyncVerifyJWTandLevel,
fastify.asyncVerifyUserAndPassword
]),
handler: (req, reply) => {
req.log.info('Auth route')
reply.send({ hello: 'world' })
}
})
})
```
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 `.after()` callback.
For a complete example implementation, see [example.js](example.js).
`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.
Any successful authentication will automatically stop `fastify-auth` from trying the rest, unless you provide the `run: 'all'` parameter:
```js
fastify.route({
method: 'GET',
url: '/run-all',
preHandler: fastify.auth([
(request, reply, done) => { console.log('executed 1'); done() },
(request, reply, done) => { console.log('executed 2'); done() },
(request, reply, done) => { console.log('executed 3'); done(new Error('you are not authenticated')) },
(request, reply, done) => { console.log('executed 4'); done() },
(request, reply, done) => { console.log('executed 5'); done(new Error('you shall not pass')) }
], { run: 'all' }),
handler: (req, reply) => { reply.send({ hello: 'world' }) }
})
```
This example will show all the console logs and will reply always with `401: you are not authenticated`.
The `run` parameter is useful if you are adding to the request business data read from auth-tokens.
You can use this plugin on route level, as in the above example or on hook level, by using the `preHandler` hook:
```js
fastify.addHook('preHandler', fastify.auth([
fastify.verifyJWTandLevel,
fastify.verifyUserAndPassword
]))
fastify.route({
method: 'POST',
url: '/auth-multiple',
handler: (req, reply) => {
req.log.info('Auth route')
reply.send({ hello: 'world' })
}
})
```
The difference between the two approaches is that if you use the route level `preHandler` function the authentication will run just for the selected route. Whereas if you use the `preHandler` hook the authentication will run for all the routes declared inside the current plugin (and its descendants).
## Acknowledgements
This project is kindly sponsored by:
- [LetzDoIt](https://www.letzdoitapp.com/)
## License
Licensed under [MIT](./LICENSE).