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

@fastify/auth

Package Overview
Dependencies
Maintainers
19
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fastify/auth - npm Package Compare versions

Comparing version 4.2.0 to 4.3.0

.taprc

2

auth.d.ts

@@ -6,3 +6,3 @@ import { ContextConfigDefault, RouteGenericInterface, FastifyInstance, FastifyPluginCallback, FastifyReply, FastifyRequest, FastifySchema, preHandlerHookHandler } from 'fastify';

auth(
functions: fastifyAuth.FastifyAuthFunction[],
functions: fastifyAuth.FastifyAuthFunction[] | (fastifyAuth.FastifyAuthFunction | fastifyAuth.FastifyAuthFunction[])[],
options?: {

@@ -9,0 +9,0 @@ relation?: 'and' | 'or',

@@ -42,3 +42,10 @@ 'use strict'

for (var i = 0; i < functions.length; i++) {
functions[i] = functions[i].bind(this)
if (Array.isArray(functions[i]) === false) {
functions[i] = [functions[i].bind(this)]
} else {
/* eslint-disable-next-line no-var */
for (var j = 0; j < functions[i].length; j++) {
functions[i][j] = functions[i][j].bind(this)
}
}
}

@@ -57,4 +64,5 @@

obj.i = 0
obj.start = true
obj.j = 0
obj.firstResult = null
obj.sufficient = false

@@ -69,3 +77,3 @@ obj.nextAuth()

this.i = 0
this.start = true
this.j = 0
this.functions = []

@@ -77,2 +85,3 @@ this.options = {}

this.firstResult = null
this.sufficient = false

@@ -82,6 +91,6 @@ const that = this

this.nextAuth = function nextAuth (err) {
const func = that.functions[that.i++]
const func = that.functions[that.i][that.j++]
if (!func) {
that.completeAuth(err)
that.completeAuthArray(err)
return

@@ -102,27 +111,44 @@ }

this.onAuth = function onAuth (err, results) {
if (that.options.relation === 'or') {
if (err) {
return that.nextAuth(err)
if (err) {
return that.completeAuthArray(err)
}
return that.nextAuth(err)
}
this.completeAuthArray = function (err) {
if (err) {
if (that.options.relation === 'and') {
if (that.options.run === 'all') {
that.firstResult = that.firstResult ?? err
} else {
that.firstResult = err
this.completeAuth()
return
}
} else {
that.firstResult = that.sufficient ? null : err
}
} else {
if (that.options.relation === 'or') {
that.sufficient = true
that.firstResult = null
return that.completeAuth()
} else {
if (err) {
return that.completeAuth(err)
if (that.options.run !== 'all') {
this.completeAuth()
return
}
}
}
if (that.i < that.functions.length - 1) {
that.i += 1
that.j = 0
return that.nextAuth(err)
}
this.completeAuth()
}
this.completeAuth = function (err) {
if (that.start) {
that.start = false
that.firstResult = err
}
if (that.options.run === 'all' && that.i < that.functions.length) {
return that.nextAuth(err)
}
this.completeAuth = function () {
if (that.firstResult && (!that.reply.raw.statusCode || that.reply.raw.statusCode < 400)) {

@@ -129,0 +155,0 @@ that.reply.code(401)

{
"name": "@fastify/auth",
"version": "4.2.0",
"version": "4.3.0",
"description": "Run multiple auth functions in Fastify",

@@ -16,5 +16,4 @@ "repository": {

"test": "npm run test:unit && npm run test:typescript",
"test:ci": "standard && tap -J ./test/*.test.js --coverage-report=lcovonly && npm run test:typescript",
"test:typescript": "tsd",
"test:unit": "tap -J ./test/*.test.js"
"test:unit": "tap"
},

@@ -39,9 +38,9 @@ "keywords": [

"@fastify/type-provider-json-schema-to-ts": "^2.1.1",
"@fastify/type-provider-typebox": "^2.3.0",
"@types/node": "^18.7.14",
"@fastify/type-provider-typebox": "^3.0.0",
"@types/node": "^20.1.0",
"fastify": "^4.5.3",
"rimraf": "^3.0.2",
"rimraf": "^5.0.0",
"standard": "^17.0.0",
"tap": "^16.3.0",
"tsd": "^0.24.1"
"tsd": "^0.28.0"
},

@@ -48,0 +47,0 @@ "dependencies": {

@@ -76,2 +76,36 @@ # @fastify/auth

If you need composited authentication, such as verifying user account passwords and levels or meeting VIP eligibility criteria. e.g. [(verifyUserPassword `and` verifyLevel) `or` (verifyVIP)]
```js
fastify
.decorate('verifyUserPassword', function (request, reply, done) {
// your validation logic
done() // pass an error if the authentication fails
})
.decorate('verifyLevel', function (request, reply, done) {
// your validation logic
done() // pass an error if the authentication fails
})
.decorate('verifyVIP', 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.verifyUserPassword, fastify.verifyLevel], // The arrays within an array always have an AND relationship.
fastify.verifyVIP
], {
relation: 'or' // default relation
}),
handler: (req, reply) => {
req.log.info('Auth route')
reply.send({ hello: 'world' })
}
})
})
```
You can use the `defaultRelation` option while registering the plugin, to change the default `relation`:

@@ -156,2 +190,14 @@ ```js

## Security Considerations
### `onRequest` vs. `preHandler` hook
The main difference between the `onRequest` and `preHandler` stages of the [Fastify Lifecycle](https://www.fastify.io/docs/latest/Reference/Lifecycle/) is that the body payload is not parsed in the `onRequest` stage. Parsing the body can be a potential security risk, as it can be used for denial of service (DoS) attacks. Therefore, it is recommended to avoid parsing the body for unauthorized access.
Using the `@fastify/auth` plugin in the `preHandler` hook can result in unnecessary memory allocation if a malicious user sends a large payload in the request body and the request is unauthorized. In this case, Fastify will parse the body, even though the request is not authorized, leading to unnecessary memory allocation. To avoid this, it is recommended to use the `onRequest` hook for authentication, if the authentication method does not require the request body, such as `@fastify/jwt`, which expects the authentication in the request header.
For authentication methods that do require the request body, such as sending a token in the body, you must use the `preHandler` hook.
In mixed cases you must use the `preHandler` hook.
## API

@@ -158,0 +204,0 @@

@@ -5,3 +5,3 @@ 'use strict'

const test = t.test
const rimraf = require('rimraf')
const { rimrafSync } = require('rimraf')
const build = require('./example-async')

@@ -12,15 +12,10 @@

t.teardown(() => {
fastify.close()
rimraf('./authdb', err => {
if (err) throw err
})
t.before(() => {
rimrafSync('./authdb')
fastify = build()
})
test('boot server', t => {
t.plan(1)
rimraf('./authdb', err => {
fastify = build()
t.error(err)
})
t.teardown(async () => {
await fastify.close()
rimrafSync('./authdb')
})

@@ -27,0 +22,0 @@

@@ -73,2 +73,12 @@ 'use strict'

method: 'POST',
url: '/checkarrayand',
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',

@@ -84,2 +94,12 @@ preHandler: fastify.auth([fastify.verifyOdd, fastify.verifyBig]),

method: 'POST',
url: '/checkarrayor',
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',

@@ -95,2 +115,12 @@ preHandler: fastify.auth([fastify.verifyOdd]),

method: 'POST',
url: '/singlearrayor',
preHandler: fastify.auth([[fastify.verifyOdd]]),
handler: (req, reply) => {
req.log.info('Auth route')
reply.send({ hello: 'world' })
}
})
fastify.route({
method: 'POST',
url: '/singleand',

@@ -106,2 +136,32 @@ preHandler: fastify.auth([fastify.verifyOdd], { relation: 'and' }),

method: 'POST',
url: '/singlearrayand',
preHandler: fastify.auth([[fastify.verifyOdd]], { relation: 'and' }),
handler: (req, reply) => {
req.log.info('Auth route')
reply.send({ hello: 'world' })
}
})
fastify.route({
method: 'POST',
url: '/singlearraycheckand',
preHandler: fastify.auth([[fastify.verifyNumber, fastify.verifyOdd]]),
handler: (req, reply) => {
req.log.info('Auth route')
reply.send({ hello: 'world' })
}
})
fastify.route({
method: 'POST',
url: '/checkarrayorsingle',
preHandler: fastify.auth([[fastify.verifyNumber, fastify.verifyOdd], fastify.verifyBig]),
handler: (req, reply) => {
req.log.info('Auth route')
reply.send({ hello: 'world' })
}
})
fastify.route({
method: 'POST',
url: '/run-all-or',

@@ -108,0 +168,0 @@ preHandler: fastify.auth([fastify.verifyOdd, fastify.verifyBig, fastify.verifyNumber], { run: 'all' }),

@@ -9,10 +9,8 @@ 'use strict'

t.teardown(() => {
fastify.close()
t.teardown(async () => {
await fastify.close()
})
test('boot server', t => {
t.plan(1)
t.before(() => {
fastify = build()
t.error(false)
})

@@ -56,2 +54,38 @@

test('And Relation sucess for single [Array] case', t => {
t.plan(2)
fastify.inject({
method: 'POST',
url: '/singlearrayand',
payload: {
n: 11
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, { hello: 'world' })
})
})
test('And Relation failed for single [Array] case', t => {
t.plan(2)
fastify.inject({
method: 'POST',
url: '/singlearrayand',
payload: {
n: 10
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, {
error: 'Unauthorized',
message: '`n` is not odd',
statusCode: 401
})
})
})
test('Or Relation sucess for single case', t => {

@@ -93,2 +127,38 @@ t.plan(2)

test('Or Relation sucess for single [Array] case', t => {
t.plan(2)
fastify.inject({
method: 'POST',
url: '/singlearrayor',
payload: {
n: 11
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, { hello: 'world' })
})
})
test('Or Relation failed for single [Array] case', t => {
t.plan(2)
fastify.inject({
method: 'POST',
url: '/singlearrayor',
payload: {
n: 10
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, {
error: 'Unauthorized',
message: '`n` is not odd',
statusCode: 401
})
})
})
test('And Relation failed for first check', t => {

@@ -171,2 +241,19 @@ t.plan(2)

test('[Array] notation And Relation success', t => {
t.plan(3)
fastify.inject({
method: 'POST',
url: '/checkarrayand',
payload: {
n: 11
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, { hello: 'world' })
t.equal(res.statusCode, 200)
})
})
test('Or Relation success under first case', t => {

@@ -189,2 +276,19 @@ t.plan(3)

test('[Array] notation Or Relation success under first case', t => {
t.plan(3)
fastify.inject({
method: 'POST',
url: '/checkarrayor',
payload: {
n: 1
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, { hello: 'world' })
t.equal(res.statusCode, 200)
})
})
test('Or Relation success under second case', t => {

@@ -207,2 +311,19 @@ t.plan(3)

test('[Array] notation Or Relation success under second case', t => {
t.plan(3)
fastify.inject({
method: 'POST',
url: '/checkarrayor',
payload: {
n: 200
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, { hello: 'world' })
t.equal(res.statusCode, 200)
})
})
test('Or Relation failed for both case', t => {

@@ -228,2 +349,110 @@ t.plan(2)

test('[Array] notation Or Relation failed for both case', t => {
t.plan(2)
fastify.inject({
method: 'POST',
url: '/checkarrayor',
payload: {
n: 90
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, {
error: 'Unauthorized',
message: '`n` is not big',
statusCode: 401
})
})
})
test('single [Array] And Relation sucess', t => {
t.plan(2)
fastify.inject({
method: 'POST',
url: '/singlearraycheckand',
payload: {
n: 11
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, { hello: 'world' })
})
})
test('single [Array] And Relation failed', t => {
t.plan(2)
fastify.inject({
method: 'POST',
url: '/singlearraycheckand',
payload: {
n: 10
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, {
error: 'Unauthorized',
message: '`n` is not odd',
statusCode: 401
})
})
})
test('[Array] notation & single case Or Relation sucess under first case', t => {
t.plan(2)
fastify.inject({
method: 'POST',
url: '/checkarrayorsingle',
payload: {
n: 11
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, { hello: 'world' })
})
})
test('[Array] notation & single case Or Relation sucess under second case', t => {
t.plan(2)
fastify.inject({
method: 'POST',
url: '/checkarrayorsingle',
payload: {
n: 1002
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, { hello: 'world' })
})
})
test('[Array] notation & single case Or Relation failed', t => {
t.plan(2)
fastify.inject({
method: 'POST',
url: '/checkarrayorsingle',
payload: {
n: 2
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.same(payload, {
error: 'Unauthorized',
message: '`n` is not big',
statusCode: 401
})
})
})
test('Check run all line fail with AND', t => {

@@ -230,0 +459,0 @@ t.plan(8)

@@ -5,3 +5,3 @@ 'use strict'

const test = t.test
const rimraf = require('rimraf')
const { rimrafSync } = require('rimraf')
const build = require('./example')

@@ -12,15 +12,10 @@

t.teardown(() => {
fastify.close()
rimraf('./authdb', err => {
if (err) throw err
})
t.before(() => {
rimrafSync('./authdb')
fastify = build()
})
test('boot server', t => {
t.plan(1)
rimraf('./authdb', err => {
fastify = build()
t.error(err)
})
t.teardown(async () => {
await fastify.close()
rimrafSync('./authdb')
})

@@ -27,0 +22,0 @@

Sorry, the diff of this file is not supported yet

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