
Solid and easy to use rate limiting for hapi.
Installation · Usage · Plugin Options · Route Options · Response Headers
Follow @marcuspoehls for updates!
The Future Studio University supports development of this hapi plugin 🚀
Join the Future Studio University and Skyrocket in Node.js
A hapi plugin to prevent brute-force attacks in your app. The rate limiter uses Redis to store rate-limit related data.
hapi-rate-limitor
is built on top of these solid and awesome projects:
Each package solves its own problem perfectly. hapi-rate-limitor
composes the solutions of each problem to a solid rate limit plugin for hapi.
hapi v17 (or later) and Node.js v8 (or newer)
This plugin requires hapi v17 (or later) and uses async/await which requires Node.js v8 or newer.
Add hapi-rate-limitor
as a dependency to your project:
npm i hapi-rate-limitor
The most straight forward to use hapi-rate-limitor
is to register it to your hapi server.
This will use the default configurations of async-ratelimiter
and ioredis.
await server.register({
plugin: require('hapi-rate-limitor')
})
// went smooth like chocolate with default settings :)
Customize the plugin’s default configuration with the following options:
redis
: Object, default:undefined
- use the
redis
configuration to pass through your custom Redis configuration toioredis
- use the
extensionPoint
: String, default:'onPostAuth'
- the request lifecycle extension point for rate limiting
userAttribute
: String, default:'id'
- credentials property that identifies a user/request on dynamic rate limits. This option is used to access the value from
request.auth.credentials
.
- credentials property that identifies a user/request on dynamic rate limits. This option is used to access the value from
userLimitAttribute
: String, default:'rateLimit'
- define the property name that identifies the rate limit value on dynamic rate limit. This option is used to access the value from
request.auth.credentials
.
- define the property name that identifies the rate limit value on dynamic rate limit. This option is used to access the value from
view
: String, default:undefined
- render the view instead of throwing an error (this uses
h.view(yourView, { total, remaining, reset }).code(429)
)
- render the view instead of throwing an error (this uses
enabled
: Boolean, default:true
- enabled or disable the plugin, e.g. when running tests
skip
: Function, default:() => false
- an async function to determine whether to skip rate limiting for a given request. The
skip
function accepts the incoming request as the only argument
- an async function to determine whether to skip rate limiting for a given request. The
All other options are directly passed through to async-ratelimiter.
await server.register({
plugin: require('hapi-rate-limitor'),
options: {
redis: {
port: 6379,
host: '127.0.0.1'
},
extensionPoint: 'onPreAuth',
namespace: 'hapi-rate-limitor',
max: 2, // a maximum of 2 requests
duration: 1000 // per second (the value is in milliseconds),
userAttribute: 'id',
userLimitAttribute: 'rateLimit',
view: 'rate-limit-exceeded', // render this view when the rate limit exceeded
enabled: true
skip: async (request) => {
return request.path.includes('/admin') // example: disable rate limiting for the admin panel
}
}
})
// went smooth like chocolate :)
You can also pass a connection string to ioReds.
await server.register({
plugin: require('hapi-rate-limitor'),
options: {
redis: 'redis://lolipop:SOME_PASSWORD@dokku-redis-lolipop:6379',
extensionPoint: 'onPreAuth',
namespace: 'hapi-rate-limitor'
// ... etc
}
})
// went smooth like chocolate :)
Please check the async-ratelimiter API for all options.
Customize the plugin’s default configuration on routes. A use case for this is a login route where you want to reduce the request limit even lower than the default limit.
On routes, hapi-rate-limitor
respects all options related to rate limiting. Precisely, all options that async-ratelimiter supports. It does not accept Redis connection options or identifiers for dynamic rate limiting.
All other options are directly passed through to async-ratelimiter.
await server.register({
plugin: require('hapi-rate-limitor'),
options: {
redis: {
port: 6379,
host: '127.0.0.1'
},
namespace: 'hapi-rate-limitor',
max: 60, // a maximum of 60 requests
duration: 60 * 1000, // per minute (the value is in milliseconds)
}
})
await server.route({
method: 'POST',
path: '/login',
options: {
handler: () {
// do the login handling
},
plugins: {
'hapi-rate-limitor': {
max: 5, // a maximum of 5 requests
duration: 60 * 1000, // per minute
enabled: false // but it’s actually not enabled ;-)
}
}
}
})
// went smooth like chocolate :)
Please check the async-ratelimiter API for all options.
To make use of user-specific rate limits, you need to configure the userIdKey
and userLimitKey
attributes in the hapi-rate-limitor
options. These attributes are used to determine the rate limit properties. The userIdKey
is the property name that uniquely identifies a user. The userLimitKey
is the property name that contains the rate limit value.
await server.register({
plugin: require('hapi-rate-limitor'),
options: {
userLimitId: 'id',
userLimitKey: 'rateLimit',
max: 500, // a maximum of 500 requests (default is 2500)
duration: 60 * 60 * 1000 // per hour (the value is in milliseconds)
// other plugin options
}
})
This will calculate the maximum requests individually for each authenticated user based on the user’s id
and 'rateLimit'
attributes. Imagine the following user object as an authenticated user:
/**
* the authenticated user object may contain
* a custom rate limit attribute. In this
* case, it’s called "rateLimit".
*/
request.auth.credentials = {
id: 'custom-uuid',
rateLimit: 1750,
name: 'Marcus'
// ... further attributes
}
For this specific user, the maximum amount of requests is 1750
per hour (and not the plugin’s default 500
).
hapi-rate-limitor
uses the plugin’s limit if the request is unauthenticated or request.auth.credentials
doesn’t contain a rate-limit-related attribute.
The plugin sets the following response headers:
X-Rate-Limit-Limit
: total request limit (max
) withinduration
X-Rate-Limit-Remaining
: remaining quota until resetX-Rate-Limit-Reset
: time since epoch in seconds that the rate limiting period will end
Do you miss a feature? Please don’t hesitate to create an issue with a short description of your desired addition to this plugin.
- hapi tutorial series with 100+ tutorials
- Create a fork
- Create your feature branch:
git checkout -b my-feature
- Commit your changes:
git commit -am 'Add some feature'
- Push to the branch:
git push origin my-new-feature
- Submit a pull request 🚀
MIT © Future Studio
futurestud.io · GitHub @futurestudio · Twitter @futurestud_io