Skip to content

Commit d3c40a7

Browse files
committed
🏄
0 parents  commit d3c40a7

File tree

10 files changed

+584
-0
lines changed

10 files changed

+584
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
reports/

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
language: node_js
2+
3+
node_js:
4+
- 0.10

LICENSE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2014 Jordan Stout
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in
11+
all copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

Makefile

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
REPORTER = dot
2+
MOCHA = ./node_modules/.bin/mocha
3+
_MOCHA = ./node_modules/.bin/_mocha
4+
ISTANBUL = ./node_modules/.bin/istanbul
5+
TESTS = test/**/*.test.js
6+
7+
test:
8+
@NODE_ENV=test $(MOCHA) \
9+
--ui exports \
10+
--reporter $(REPORTER) \
11+
--async-only \
12+
$(TESTS)
13+
14+
test-w:
15+
@NODE_ENV=test $(MOCHA) \
16+
--ui exports \
17+
--reporter $(REPORTER) \
18+
--async-only \
19+
--growl \
20+
--watch \
21+
$(TESTS)
22+
23+
coverage:
24+
@test -d reports || mkdir reports
25+
$(ISTANBUL) cover --report html --dir ./reports $(_MOCHA) -- -A -u exports -R spec $(TESTS)
26+
27+
.PHONY: test test-w

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
### hapi-auth-bearer
2+
3+
[![Build Status](https://travis-ci.org/j/hapi-auth-bearer.png?branch=master)](https://travis-ci.org/j/hapi-auth-bearer)
4+
5+
#### Bearer authentication
6+
7+
This scheme requires the following options:
8+
9+
- `validateFunc` - Function with signature `function(secretOrToken, callback)` where:
10+
- `secretOrToken` - the `secret` if option `base64: true` is set, otherwise the raw token value is passed in.
11+
- `callback` - the callback function with signature `function(err, credentials)` where:
12+
- `err` - an internal error.
13+
- `credentials` - a credentials object that gets passed back to the application in `request.auth.credentials`.
14+
Return `null` or `undefined` to when the credentials are unknown (and not an error). Also, credentials
15+
object MUST contain a key `token` when using `base64: true` option so that we can validate the header
16+
token from the token stored in the database. (This makes it so that you only need to index `secret` instead
17+
of both `secret` and `token` for smaller storage. Just simply do a find on secret, and pass back the token
18+
value.
19+
20+
- `base64` - Boolean value (defaults to `false` aka just accepts a raw token value). This gives you the ability to pass
21+
back a base64 encoded authorization header: base64(SECRET:TOKEN)
22+
- i.e.) Bearer NTJlYjRmZmRmM2M3MjNmZjA1MTEwYmYxOjk5ZWQyZjdmMWRiNjBiZDBlNGY1ZjQ4ZjRhMWVhNWVjMmE4NzU2ZmU=
23+
24+
25+
```javascript
26+
var Hapi = require('hapi');
27+
var server = new Hapi.Server();
28+
29+
var credentials = {
30+
// without base64
31+
someSuperSecureToken: {
32+
user: { /** ... */ }
33+
},
34+
// for base64
35+
shhImASecret: {
36+
token: 'someSuperSecureToken',
37+
user: { /** ... */ }
38+
}
39+
};
40+
41+
var validateFunc = function (id, callback) {
42+
return callback(null, credentials[id]);
43+
};
44+
45+
server.pack.require('hapi-auth-bearer', function (err) {
46+
server.auth.strategy('bearer', 'bearer', { validateFunc: validateFunc });
47+
48+
server.auth.strategy('bearer-base64', 'bearer', {
49+
base64: true,
50+
validateFunc: validateFunc
51+
});
52+
});
53+
54+
```

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./lib');

lib/index.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
var boom = require('boom');
2+
var hoek = require('hoek');
3+
4+
/**
5+
* Simple Bearer auth token strategy.
6+
*
7+
* If `options.base64` is set to `true`, then it expects a base64 encoded value of SECRET:TOKEN, otherwise
8+
* it expects the Bearer value to just be the token.
9+
* i.e.) Bearer NTJlYjRmZmRmM2M3MjNmZjA1MTEwYmYxOjk5ZWQyZjdmMWRiNjBiZDBlNGY1ZjQ4ZjRhMWVhNWVjMmE4NzU2ZmU=
10+
*
11+
*
12+
* @param server
13+
* @param {Object} options
14+
*
15+
* @returns {{authenticate: Function}}
16+
*/
17+
var bearerScheme = function bearerScheme(server, options) {
18+
hoek.assert(options && 'object' === typeof options, 'Missing Bearer auth strategy options');
19+
20+
hoek.assert(
21+
options && 'function' === typeof options.validateFunc,
22+
'options.validateFunc must be a valid function in Bearer scheme'
23+
);
24+
25+
options.base64 = options.base64 || false;
26+
27+
return {
28+
authenticate: function (request, reply) {
29+
var req = request.raw.req;
30+
var authorization = req.headers.authorization;
31+
32+
if (!authorization) {
33+
return reply(boom.unauthorized(null, 'Bearer'));
34+
}
35+
36+
var parts = authorization.split(/\s+/);
37+
38+
if (parts.length !== 2) {
39+
return reply(boom.badRequest('Bad HTTP authentication header format'));
40+
}
41+
42+
if (parts[0] && parts[0].toLowerCase() !== 'bearer') {
43+
return reply(boom.unauthorized(null, 'Bearer'));
44+
}
45+
46+
var createCallback = function(secret, token) {
47+
return function (err, credentials) {
48+
if (err) {
49+
return reply(err, { credentials: credentials, log: { tags: ['auth', 'bearer-auth'], data: err } });
50+
}
51+
52+
if (!credentials || (token && (!credentials.token || credentials.token !== token))) {
53+
return reply(boom.unauthorized('Invalid token', 'Bearer'), { credentials: credentials });
54+
}
55+
56+
return reply(null, { credentials: credentials });
57+
}
58+
};
59+
60+
if (options.base64) {
61+
var tokenParts = new Buffer(parts[1] || '', 'base64').toString('utf8').split(':');
62+
if (tokenParts.length !== 2) {
63+
return reply(boom.badRequest('Bad HTTP authentication token value format'));
64+
}
65+
66+
return options.validateFunc(tokenParts[0], createCallback(tokenParts[0], tokenParts[1]));
67+
} else {
68+
return options.validateFunc(parts[1], createCallback(null, parts[1]));
69+
}
70+
}
71+
};
72+
};
73+
74+
75+
exports.register = function (plugin, options, next) {
76+
plugin.auth.scheme('bearer', bearerScheme);
77+
next();
78+
};

0 commit comments

Comments
 (0)