-
-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathReadme.md
165 lines (133 loc) · 6.5 KB
/
Readme.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# @fastify/bearer-auth
[![CI](https://github.com/fastify/fastify-bearer-auth/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/fastify/fastify-bearer-auth/actions/workflows/ci.yml)
[![npm version](https://img.shields.io/npm/v/@fastify/bearer-auth)](https://www.npmjs.com/package/@fastify/bearer-auth)
[![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)
*@fastify/bearer-auth* provides a simple Bearer auth request hook for the [Fastify][fastify]
web framework.
[fastify]: https://fastify.dev/
## Install
```
npm i @fastify/bearer-auth
```
### Compatibility
| Plugin version | Fastify version |
| ---------------|-----------------|
| `^10.x` | `^5.x` |
| `^8.x` | `^4.x` |
| `^5.x` | `^3.x` |
| `^4.x` | `^2.x` |
| `^1.x` | `^1.x` |
Please note that if a Fastify version is out of support, then so are the corresponding versions of this plugin
in the table above.
See [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details.
## Example
```js
'use strict'
const fastify = require('fastify')()
const bearerAuthPlugin = require('@fastify/bearer-auth')
const keys = new Set(['a-super-secret-key', 'another-super-secret-key'])
fastify.register(bearerAuthPlugin, {keys})
fastify.get('/foo', (req, reply) => {
reply.send({authenticated: true})
})
fastify.listen({port: 8000}, (err) => {
if (err) {
fastify.log.error(err.message)
process.exit(1)
}
fastify.log.info('http://127.0.0.1:8000/foo')
})
```
## API
*@fastify/bearer-auth* exports a standard [Fastify plugin](https://github.com/fastify/fastify-plugin). This allows
you to register the plugin within scoped paths. Therefore, you could have some
paths not protected by the plugin and others that are. See the [Fastify](https://fastify.dev/docs/latest)
documentation and examples for more details.
When registering the plugin you must specify a configuration object:
* `keys`: A `Set` or array with valid keys of type `string` (required)
* `function errorResponse (err) {}`: method must synchronously return the content body to be
sent to the client (optional)
* `contentType`: If the content to be sent is anything other than
`application/json`, then the `contentType` property must be set (optional)
* `bearerType`: string specifying the Bearer string (optional)
* `specCompliance`:
Plugin spec compliance. Accepts either
[`rfc6749`](https://datatracker.ietf.org/doc/html/rfc6749) or
[`rfc6750`](https://datatracker.ietf.org/doc/html/rfc6750).
Defaults to `rfc6750`.
* `rfc6749` is about the generic OAuth2.0 protocol, which allows the token type to be case-insensitive
* `rfc6750` is about the Bearer Token Usage, which forces the token type to be an exact match
* `function auth (key, req) {}` : this function will test if `key` is a valid token.
The function must return a literal `true` if the key is accepted or a literal
`false` if rejected. The function may also return a promise that resolves to
one of these values. If the function returns or resolves to any other value,
rejects, or throws, an HTTP status of `500` will be sent. `req` is the Fastify
request object. If `auth` is a function, `keys` will be ignored. If `auth` is
not a function, or `undefined`, `keys` will be used.
* `addHook`: If `false`, this plugin will not register `onRequest` hook automatically,
instead it provides two decorations `fastify.verifyBearerAuth` and
`fastify.verifyBearerAuthFactory` for you.
* `verifyErrorLogLevel`: An optional string specifying the log level when there is a verification error.
It must be a valid log level supported by fastify, otherwise, an exception will be thrown
when registering the plugin. By default, this option is set to `error`.
The default configuration object is:
```js
{
keys: new Set(),
contentType: undefined,
bearerType: 'Bearer',
specCompliance: 'rfc6750',
errorResponse: (err) => {
return {error: err.message}
},
auth: undefined,
addHook: true
}
```
Internally, the plugin registers a standard *Fastify* [preHandler hook][prehook],
which will inspect the request's headers for an `authorization` header with the
format `bearer key`. The `key` will be matched against the configured `keys`
object via a [constant time algorithm](https://en.wikipedia.org/wiki/Time_complexity#Constant_time) to prevent against [timing-attacks](https://snyk.io/blog/node-js-timing-attack-ccc-ctf/). If the `authorization` header is missing,
malformed, or the `key` does not validate then a 401 response will be sent with
a `{error: message}` body; no further request processing will be performed.
[fplugin]: https://github.com/fastify/fastify/blob/main/docs/Reference/Plugins.md
[prehook]: https://github.com/fastify/fastify/blob/main/docs/Reference/Hooks.md
## Integration with `@fastify/auth`
This plugin can integrate with `@fastify/auth` by following this example:
```js
const fastify = require('fastify')()
const auth = require('@fastify/auth')
const bearerAuthPlugin = require('@fastify/bearer-auth')
const keys = new Set(['a-super-secret-key', 'another-super-secret-key'])
async function server() {
await fastify
.register(auth)
.register(bearerAuthPlugin, { addHook: false, keys, verifyErrorLogLevel: 'debug' })
.decorate('allowAnonymous', function (req, reply, done) {
if (req.headers.authorization) {
return done(Error('not anonymous'))
}
return done()
})
fastify.route({
method: 'GET',
url: '/multiauth',
preHandler: fastify.auth([
fastify.allowAnonymous,
fastify.verifyBearerAuth
]),
handler: function (_, reply) {
reply.send({ hello: 'world' })
}
})
await fastify.listen({port: 8000})
}
server()
```
By passing `{ addHook: false }` in the options, the `verifyBearerAuth` hook, instead of
immediately replying on error (`reply.send(someError)`), invokes `done(someError)`. This
will allow `fastify.auth` to continue with the next authentication scheme in the hook list.
Note that by setting `{ verifyErrorLogLevel: 'debug' }` in the options, `@fastify/bearer-auth` will emit all verification error logs at the `debug` level. Since it is not the only authentication method here, emitting verification error logs at the `error` level may be not appropriate here.
If `verifyBearerAuth` is the last hook in the list, `fastify.auth` will reply with `Unauthorized`.
## License
Licensed under [MIT](./LICENSE).