Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for custom middleware to handle unauthorized. #24

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
### [1.3.3](https://github.com/matmar10/express-basic-auth/compare/v1.3.2...v1.3.3) (2021-08-07)


### Continuous Integration

* remove typescript compiler check from build test ([2579b12](https://github.com/matmar10/express-basic-auth/commit/2579b125f2ccf376b32cd04376a1b11f48761378))


### Documentation

* update badges to new forked repo ([3ac09ed](https://github.com/matmar10/express-basic-auth/commit/3ac09ed68d12177edc14b257bfb7756d3256fad3))

### [1.3.2](https://github.com/matmar10/express-basic-auth/compare/v1.3.1...v1.3.2) (2021-08-07)


### Documentation

* point to fork & add contributors ([72bf15b](https://github.com/matmar10/express-basic-auth/commit/72bf15b58e76f65cda015c0faca996067ff2f89c))

### [1.3.1](https://github.com/LionC/express-basic-auth/compare/v1.3.0...v1.3.1) (2021-08-07)

## [1.3.0](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2021-08-07)


### Features

* enable custom unauthorized handling via middleware ([8d3c2e1](https://github.com/LionC/express-basic-auth/commit/8d3c2e1b32131daee6686c8922de86fdbd91d01d)), closes [#23](https://github.com/LionC/express-basic-auth/issues/23)


### Documentation

* add release script using conventional commit changelog ([e13b2d6](https://github.com/LionC/express-basic-auth/commit/e13b2d623fb31636ff029b6ba1613294aa634044))

## [1.2.0](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2019-04-22)

### [1.1.7](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2019-04-22)

### [1.1.6](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2018-10-26)

### [1.1.5](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2018-04-23)

### [1.1.4](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2018-02-09)

### [1.1.3](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2017-10-23)

### [1.1.2](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2017-08-15)

### [1.1.1](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2017-05-29)

## [1.1.0](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2017-05-29)

### [1.0.2](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2017-04-27)

### [1.0.1](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2017-03-18)

## [1.0.0](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2017-02-16)

### [0.3.3](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2017-02-16)

### [0.3.2](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2017-02-14)

### [0.3.1](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2017-02-14)

## [0.3.0](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2017-02-14)

### [0.2.3](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2016-11-07)

### [0.2.2](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2016-10-19)

### [0.2.1](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2016-10-18)

## [0.2.0](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2016-10-18)

### [0.1.3](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2016-10-15)

### [0.1.2](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2016-10-11)

### [0.1.1](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2016-10-11)

## [0.1.0](https://github.com/LionC/express-basic-auth/compare/v1.2.0...v1.3.0) (2016-10-11)

63 changes: 50 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# express-basic-auth

[![npm version](https://badge.fury.io/js/express-basic-auth.svg)](https://badge.fury.io/js/express-basic-auth)
[![npm](https://img.shields.io/npm/dm/express-basic-auth.svg)]()
[![CircleCI](https://circleci.com/gh/LionC/express-basic-auth/tree/master.svg?style=shield&circle-token=74f7b1557100b45259e67d2492c263e4f99365d4)](https://circleci.com/gh/LionC/express-basic-auth/tree/master)
[![npm version](https://badge.fury.io/js/%40blossomfinance%2Fexpress-basic-auth.svg)](https://badge.fury.io/js/%40blossomfinance%2Fexpress-basic-auth)
![npm (scoped)](https://img.shields.io/npm/v/@blossomfinance/express-basic-auth)
[![CircleCI](https://circleci.com/gh/matmar10/express-basic-auth/tree/master.svg?style=svg)](https://circleci.com/gh/matmar10/express-basic-auth/tree/master)
[![David](https://img.shields.io/david/strongloop/express.svg)]()
![TypeScript compatible](https://img.shields.io/badge/typescript-compatible-brightgreen.svg)
[![MIT Licence](https://badges.frapsoft.com/os/mit/mit.svg?v=103)](https://opensource.org/licenses/mit-license.php)
Expand Down Expand Up @@ -116,22 +116,59 @@ function myAsyncAuthorizer(username, password, cb) {
### Unauthorized Response Body

Per default, the response body for unauthorized responses will be empty. It can
be configured using the `unauthorizedResponse` option. You can either pass a
static response or a function that gets passed the express request object and is
expected to return the response body. If the response body is a string, it will
be used as-is, otherwise it will be sent as JSON:
be configured using the `unauthorizedResponse` option.

You can pass one of the following:

- a static value (string or object)
- a function that synchronously returns a value (string or object)
- a middleware

If a string value is returned or produced by the function, it will be
sent as-is as the response along with a 401 status code. Ohterwise,
it will be sent as json via the `.json` method.


```js

// static value
app.use(basicAuth({
users: { 'Foo': 'bar' },
unauthorizedResponse: getUnauthorizedResponse
unauthorizedResponse: 'Sorry, you are not authorized.'
}))

// a function that synchronously returns a value
app.use(basicAuth({
users: { 'Foo': 'bar' },
unauthorizedResponse: function (req) {
return req.auth
? ('Credentials ' + req.auth.user + ':' + req.auth.password + ' rejected')
: 'No credentials provided'
}
}))

// a middleware
app.use(basicAuth({
users: { 'Foo': 'bar' },
unauthorizedResponse: function (req, res, next) {
if (req.auth) {
next(new Error('Login required'));
return;
}
// or send an html page
if (req.accepts('html') {
res.render('unauthorized');
return;
}
// or whatever you like!
res.status(403)
.set('X-Toynbee-Idea', 'In Kubrick’s 2001 Resurrect Dead On Planet Jupiter')
.send({
message: 'Future authorization attempts are futile.'
});
}
}))

function getUnauthorizedResponse(req) {
return req.auth
? ('Credentials ' + req.auth.user + ':' + req.auth.password + ' rejected')
: 'No credentials provided'
}
```

### Challenge
Expand Down
29 changes: 26 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function buildMiddleware(options) {
var users = options.users || {}
var authorizer = options.authorizer || staticUsersAuthorizer
var isAsync = options.authorizeAsync != undefined ? !!options.authorizeAsync : false
var getResponseBody = ensureFunction(options.unauthorizedResponse, '')
var handleUnauthorizedResponse = ensureFunction(options.unauthorizedResponse, '')
var realm = ensureFunction(options.realm)

assert(typeof users == 'object', 'Expected an object for the basic auth users, found ' + typeof users + ' instead')
Expand Down Expand Up @@ -74,9 +74,32 @@ function buildMiddleware(options) {
res.set('WWW-Authenticate', challengeString)
}

//TODO: Allow response body to be JSON (maybe autodetect?)
const response = getResponseBody(req)
// normally we can assume no value returned means using a middleware
// but this check is needed in case they follow the
// `return res.send();`
// pattern
function isFinishedExpressResponse(res) {
if (!res) {
return false;
}
// ServerResponse type indicates they reutnred res or res.something()
// which indicates a middleware in use
if (!res.constructor || -1 === res.constructor.toString().indexOf('ServerResponse')) {
return false;
}
// NOTE: this will never send a response if they forgot to call .send()
return true;
}

const response = handleUnauthorizedResponse(req, res, next)
// if no response, assume middleware
if ((!response && response !== '') || isFinishedExpressResponse(response)) {
// already fully handled as middleware and let it go
return;
}

// sync response, including '' which is the default body
// so just send that value
if(typeof response == 'string')
return res.status(401).send(response)

Expand Down
Loading