-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
61 lines (50 loc) · 2.06 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
* @param allowScopes {(string|Array<string>)} - Allowed or required scopes. String must be 'space' separated
* @param options {Object} - Options
* - scopeKey {string} [scope] - The user property name to check for the scope. req.auth[scopeKey]
* - requireAll {boolean} [false] - If true: all scopes must be included. If false: at least 1
* - errorToNext {boolean} [false] - If true: forward errors to 'next', instead of ending the response directly
* @returns {Function}
*/
module.exports = (allowScopes, options = {}) => {
options.scopeKey = options && options.scopeKey || 'scope';
if (typeof allowScopes === 'string')
allowScopes = allowScopes.split(' ');
if (!Array.isArray(allowScopes)) {
throw new Error('Parameter allowScopes must be a string or an array of strings.');
}
return (req, res, next) => {
const error = res => {
const err_message = 'Insufficient scope';
// Forward errors to next instead of ending the response directly
if (options && options.errorToNext)
return next({statusCode: 403, error: 'Forbidden', message: err_message});
// To follow RFC 6750
// see https://tools.ietf.org/html/rfc6750#page-7
res.append(
'WWW-Authenticate',
`Bearer scope="${allowScopes.join(' ')}", error="${err_message}"`
);
res.status(403).send(err_message);
};
if (allowScopes.length === 0) {
return next();
}
if (!req.auth) return error(res);
let userScopes = [];
const scopeKey = options.scopeKey;
// Allow 'space' seperated string value or array value
if (typeof req.auth[scopeKey] === 'string') {
userScopes = req.auth[scopeKey].split(' ');
} else if (Array.isArray(req.auth[scopeKey])) {
userScopes = req.auth[scopeKey];
} else return error(res);
let isAllowed;
if (options && options.requireAll) {
isAllowed = allowScopes.every(scope => userScopes.includes(scope));
} else {
isAllowed = allowScopes.some(scope => userScopes.includes(scope));
}
return isAllowed ? next() : error(res);
};
};