fastify-basic-auth
Advanced tools
Comparing version 1.2.0 to 2.0.0
49
index.js
@@ -7,16 +7,11 @@ 'use strict' | ||
function basicPlugin (fastify, opts, next) { | ||
async function basicPlugin (fastify, opts) { | ||
if (typeof opts.validate !== 'function') { | ||
return next(new Error('Basic Auth: Missing validate function')) | ||
throw new Error('Basic Auth: Missing validate function') | ||
} | ||
const authenticateHeader = getAuthenticateHeader(opts.authenticate, next) | ||
const authenticateHeader = getAuthenticateHeader(opts.authenticate) | ||
const validate = opts.validate.bind(fastify) | ||
fastify.decorate('basicAuth', basicAuth) | ||
next() | ||
function basicAuth (req, reply, next) { | ||
if (authenticateHeader) { | ||
reply.header(authenticateHeader.key, authenticateHeader.value) | ||
} | ||
const credentials = auth(req) | ||
@@ -38,2 +33,13 @@ if (credentials == null) { | ||
} | ||
if (err.statusCode === 401) { | ||
switch (typeof authenticateHeader) { | ||
case 'string': | ||
reply.header('WWW-Authenticate', authenticateHeader) | ||
break | ||
case 'function': | ||
reply.header('WWW-Authenticate', authenticateHeader(req)) | ||
break | ||
} | ||
} | ||
next(err) | ||
@@ -47,21 +53,24 @@ } else { | ||
function getAuthenticateHeader (authenticate, next) { | ||
function getAuthenticateHeader (authenticate) { | ||
if (!authenticate) return false | ||
if (authenticate === true) { | ||
return { | ||
key: 'WWW-Authenticate', | ||
value: 'Basic' | ||
} | ||
return 'Basic' | ||
} | ||
if (typeof authenticate === 'object') { | ||
const realm = (authenticate.realm && typeof authenticate.realm === 'string') | ||
? authenticate.realm | ||
: '' | ||
return { | ||
key: 'WWW-Authenticate', | ||
value: 'Basic' + (realm ? ` realm="${realm}"` : '') | ||
const realm = authenticate.realm | ||
switch (typeof realm) { | ||
case 'undefined': | ||
return 'Basic' | ||
case 'boolean': | ||
return 'Basic' | ||
case 'string': | ||
return `Basic realm="${realm}"` | ||
case 'function': | ||
return function (req) { | ||
return `Basic realm="${realm(req)}"` | ||
} | ||
} | ||
} | ||
next(new Error('Basic Auth: Invalid authenticate option')) | ||
throw new Error('Basic Auth: Invalid authenticate option') | ||
} | ||
@@ -68,0 +77,0 @@ |
{ | ||
"name": "fastify-basic-auth", | ||
"version": "1.2.0", | ||
"version": "2.0.0", | ||
"description": "Fastify basic auth plugin", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -169,5 +169,18 @@ # fastify-basic-auth | ||
The `realm` key could also be a function: | ||
```js | ||
fastify.register(require('fastify-basic-auth'), { | ||
validate, | ||
authenticate: { | ||
realm(req) { | ||
return 'example' // WWW-Authenticate: Basic realm="example" | ||
} | ||
} | ||
}) | ||
``` | ||
## License | ||
Licensed under [MIT](./LICENSE). |
179
test.js
@@ -168,3 +168,3 @@ 'use strict' | ||
test('WWW-Authenticate (authenticate: true)', t => { | ||
t.plan(3) | ||
t.plan(6) | ||
@@ -196,2 +196,11 @@ const fastify = Fastify() | ||
url: '/', | ||
method: 'GET' | ||
}, (err, res) => { | ||
t.error(err) | ||
t.equal(res.headers['www-authenticate'], 'Basic') | ||
t.equal(res.statusCode, 401) | ||
}) | ||
fastify.inject({ | ||
url: '/', | ||
method: 'GET', | ||
@@ -202,4 +211,4 @@ headers: { | ||
}, (err, res) => { | ||
t.equal(res.headers['www-authenticate'], 'Basic') | ||
t.error(err) | ||
t.equal(res.headers['www-authenticate'], undefined) | ||
t.equal(res.statusCode, 200) | ||
@@ -210,3 +219,3 @@ }) | ||
test('WWW-Authenticate Realm (authenticate: {realm: "example"})', t => { | ||
t.plan(3) | ||
t.plan(6) | ||
@@ -238,2 +247,11 @@ const fastify = Fastify() | ||
url: '/', | ||
method: 'GET' | ||
}, (err, res) => { | ||
t.error(err) | ||
t.equal(res.headers['www-authenticate'], 'Basic realm="example"') | ||
t.equal(res.statusCode, 401) | ||
}) | ||
fastify.inject({ | ||
url: '/', | ||
method: 'GET', | ||
@@ -244,4 +262,4 @@ headers: { | ||
}, (err, res) => { | ||
t.equal(res.headers['www-authenticate'], 'Basic realm="example"') | ||
t.error(err) | ||
t.equal(res.headers['www-authenticate'], undefined) | ||
t.equal(res.statusCode, 200) | ||
@@ -581,3 +599,3 @@ }) | ||
test('Invalid options (authenticate realm)', t => { | ||
t.plan(3) | ||
t.plan(6) | ||
@@ -609,2 +627,11 @@ const fastify = Fastify() | ||
url: '/', | ||
method: 'GET' | ||
}, (err, res) => { | ||
t.error(err) | ||
t.equal(res.headers['www-authenticate'], 'Basic') | ||
t.equal(res.statusCode, 401) | ||
}) | ||
fastify.inject({ | ||
url: '/', | ||
method: 'GET', | ||
@@ -615,4 +642,52 @@ headers: { | ||
}, (err, res) => { | ||
t.error(err) | ||
t.equal(res.headers['www-authenticate'], undefined) | ||
t.equal(res.statusCode, 200) | ||
}) | ||
}) | ||
test('Invalid options (authenticate realm = undefined)', t => { | ||
t.plan(6) | ||
const fastify = Fastify() | ||
fastify | ||
.register(basicAuth, { validate, authenticate: { realm: undefined } }) | ||
function validate (username, password, req, res, done) { | ||
if (username === 'user' && password === 'pwd') { | ||
done() | ||
} else { | ||
done(new Error('Unauthorized')) | ||
} | ||
} | ||
fastify.after(() => { | ||
fastify.route({ | ||
method: 'GET', | ||
url: '/', | ||
preHandler: fastify.basicAuth, | ||
handler: (req, reply) => { | ||
reply.send({ hello: 'world' }) | ||
} | ||
}) | ||
}) | ||
fastify.inject({ | ||
url: '/', | ||
method: 'GET' | ||
}, (err, res) => { | ||
t.error(err) | ||
t.equal(res.headers['www-authenticate'], 'Basic') | ||
t.equal(res.statusCode, 401) | ||
}) | ||
fastify.inject({ | ||
url: '/', | ||
method: 'GET', | ||
headers: { | ||
authorization: basicAuthHeader('user', 'pwd') | ||
} | ||
}, (err, res) => { | ||
t.error(err) | ||
t.equal(res.headers['www-authenticate'], undefined) | ||
t.equal(res.statusCode, 200) | ||
@@ -622,4 +697,98 @@ }) | ||
test('WWW-Authenticate Realm (authenticate: {realm (req) { }})', t => { | ||
t.plan(7) | ||
const fastify = Fastify() | ||
const authenticate = { | ||
realm (req) { | ||
t.equal(req.url, '/') | ||
return 'root' | ||
} | ||
} | ||
fastify.register(basicAuth, { validate, authenticate }) | ||
function validate (username, password, req, res, done) { | ||
if (username === 'user' && password === 'pwd') { | ||
done() | ||
} else { | ||
done(new Error('Unauthorized')) | ||
} | ||
} | ||
fastify.after(() => { | ||
fastify.route({ | ||
method: 'GET', | ||
url: '/', | ||
preHandler: fastify.basicAuth, | ||
handler: (req, reply) => { | ||
reply.send({ hello: 'world' }) | ||
} | ||
}) | ||
}) | ||
fastify.inject({ | ||
url: '/', | ||
method: 'GET' | ||
}, (err, res) => { | ||
t.error(err) | ||
t.equal(res.headers['www-authenticate'], 'Basic realm="root"') | ||
t.equal(res.statusCode, 401) | ||
}) | ||
fastify.inject({ | ||
url: '/', | ||
method: 'GET', | ||
headers: { | ||
authorization: basicAuthHeader('user', 'pwd') | ||
} | ||
}, (err, res) => { | ||
t.error(err) | ||
t.equal(res.headers['www-authenticate'], undefined) | ||
t.equal(res.statusCode, 200) | ||
}) | ||
}) | ||
test('No 401 no realm', t => { | ||
t.plan(4) | ||
const fastify = Fastify() | ||
fastify.register(basicAuth, { validate, authenticate: true }) | ||
function validate (username, password, req, res) { | ||
const err = new Error('Winter is coming') | ||
err.statusCode = 402 | ||
return Promise.reject(err) | ||
} | ||
fastify.after(() => { | ||
fastify.route({ | ||
method: 'GET', | ||
url: '/', | ||
preHandler: fastify.basicAuth, | ||
handler: (req, reply) => { | ||
reply.send({ hello: 'world' }) | ||
} | ||
}) | ||
}) | ||
fastify.inject({ | ||
url: '/', | ||
method: 'GET', | ||
headers: { | ||
authorization: basicAuthHeader('user', 'pwdd') | ||
} | ||
}, (err, res) => { | ||
t.error(err) | ||
t.equal(res.statusCode, 402) | ||
t.equal(res.headers['www-authenticate'], undefined) | ||
t.same(JSON.parse(res.payload), { | ||
error: 'Payment Required', | ||
message: 'Winter is coming', | ||
statusCode: 402 | ||
}) | ||
}) | ||
}) | ||
function basicAuthHeader (username, password) { | ||
return 'Basic ' + Buffer.from(`${username}:${password}`).toString('base64') | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30028
812
186