Skip to content

Commit 2688ba9

Browse files
committed
move token to fp
1 parent 321e82a commit 2688ba9

File tree

3 files changed

+143
-173
lines changed

3 files changed

+143
-173
lines changed

src/index.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ let store
2323
* public key or online with help of the Keycloak server and
2424
* JWKS. Resolve if the verification succeeded.
2525
*
26-
* @param {string} token The token to be validated
26+
* @param {string} tkn The token to be validated
2727
* @returns {Promise} The error-handled promise
2828
*/
29-
function validateSignedJwt (token) {
30-
return manager.validateToken(new Token(token, options.clientId))
29+
function validateSignedJwt (tkn) {
30+
return manager.validateToken(new Token(tkn, options.clientId))
3131
}
3232

3333
/**
@@ -38,16 +38,16 @@ function validateSignedJwt (token) {
3838
* Keycloak server, the client identifier and its secret.
3939
* Resolve if the request succeeded and token is valid.
4040
*
41-
* @param {string} token The token to be validated
41+
* @param {string} tkn The token to be validated
4242
* @returns {Promise} The error-handled promise
4343
*/
44-
function validateSecret (token) {
45-
return manager.validateAccessToken(token).then((res) => {
44+
function validateSecret (tkn) {
45+
return manager.validateAccessToken(tkn).then((res) => {
4646
if (res === false) {
4747
throw Error(error.msg.invalid)
4848
}
4949

50-
return token
50+
return tkn
5151
})
5252
}
5353

@@ -65,11 +65,11 @@ function validateSecret (token) {
6565
function handleKeycloakValidation (tkn, reply) {
6666
const validateFn = options.secret ? validateSecret : validateSignedJwt
6767

68-
validateFn(tkn.get()).then(() => {
69-
const { expiresIn, credentials } = tkn.getData(options.userInfo)
68+
validateFn(tkn).then(() => {
69+
const { expiresIn, credentials } = token.getData(tkn, options.userInfo)
7070
const userData = { credentials }
7171

72-
cache.set(store, tkn.get(), userData, expiresIn)
72+
cache.set(store, tkn, userData, expiresIn)
7373
reply.continue(userData)
7474
}).catch((err) => {
7575
reply(error('unauthorized', err, error.msg.invalid))
@@ -88,14 +88,14 @@ function handleKeycloakValidation (tkn, reply) {
8888
* @param {Function} reply The callback handler
8989
*/
9090
function validate (field, reply) {
91-
const tkn = token(field)
91+
const tkn = token.create(field)
9292
const done = fakeReply(reply)
9393

9494
if (!tkn) {
9595
return done(error('unauthorized', error.msg.missing))
9696
}
9797

98-
cache.get(store, tkn.get(), (err, cached) => {
98+
cache.get(store, tkn, (err, cached) => {
9999
const isCached = cached && !err
100100
isCached ? done.continue(cached) : handleKeycloakValidation(tkn, done)
101101
})

src/token.js

Lines changed: 107 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,155 +1,125 @@
11
const _ = require('lodash')
22

33
/**
4-
* @constructor
5-
* @public
4+
* @function
5+
* @private
66
*
7-
* Wrap JSON Web Token to enable additional features.
7+
* Extract bearer token out of header.
8+
* https://tools.ietf.org/html/rfc7519
89
*
9-
* @param {string} field The bearer token field
10-
* @returns {token} The token wrapper
10+
* @param {string} field The header field to be scanned
11+
* @returns {string} The extracted header
1112
*/
12-
function token (field) {
13-
let tkn
14-
15-
/**
16-
* @function
17-
* @private
18-
*
19-
* Extract bearer token out of header.
20-
* https://tools.ietf.org/html/rfc7519
21-
*
22-
* @param {string} header The header to be scanned
23-
* @returns {string} The extracted header
24-
*/
25-
function extractToken (header) {
26-
return /^(?:bearer) ([a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?)$/i.exec(header)
27-
}
28-
29-
/**
30-
* @function
31-
* @private
32-
*
33-
* Get scope out of token content.
34-
* Exclude `account` roles and prefix realm roles
35-
* with `realm:`. Roles of other resources are prefixed
36-
* with their name.
37-
*
38-
* @param {Object} [realm] The realm access data
39-
* @param {Object} [resource] The resource access data
40-
* @returns {Array.<?string>} The list of roles
41-
*/
42-
function getScope ({
43-
realm_access: realm = { roles: [] },
44-
resource_access: resource = {}
45-
}) {
46-
delete resource.account
47-
const realmRoles = realm.roles.map(role => `realm:${role}`)
48-
49-
const appRoles = _.flatten(_.map(resource, 'roles'))
13+
function extractToken (field) {
14+
return /^(?:bearer) ([a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?)$/i.exec(field)
15+
}
5016

51-
return [...realmRoles, ...appRoles]
52-
}
17+
/**
18+
* @function
19+
* @private
20+
*
21+
* Get scope out of token content.
22+
* Exclude `account` roles and prefix realm roles
23+
* with `realm:`. Roles of other resources are prefixed
24+
* with their name.
25+
*
26+
* @param {Object} [realm] The realm access data
27+
* @param {Object} [resource] The resource access data
28+
* @returns {Array.<?string>} The list of roles
29+
*/
30+
function getScope ({
31+
realm_access: realm = { roles: [] },
32+
resource_access: resource = {}
33+
}) {
34+
delete resource.account
35+
const realmRoles = realm.roles.map(role => `realm:${role}`)
5336

54-
/**
55-
* @function
56-
* @private
57-
*
58-
* Get expiration out of token content.
59-
*
60-
* @param {number} [exp] The `expiration` timestamp in seconds
61-
* @param {number} [iat] The `issued at` timestamp in seconds
62-
* @returns {number} The expiration delta in milliseconds
63-
*/
64-
function getExpiration ({ exp = 60, iat = 0 }) {
65-
return (exp - iat) * 1000
66-
}
37+
const appRoles = _.flatten(_.map(resource, 'roles'))
6738

68-
/**
69-
* @function
70-
* @private
71-
*
72-
* Get necessary user information out of token content.
73-
*
74-
* @param {Object} content The token its content
75-
* @param {Array.<?string>} [fields] The necessary fields
76-
* @returns {Object} The collection of requested user info
77-
*/
78-
function getUserInfo (content, fields = []) {
79-
return _.pick(content, ['sub', ...fields])
80-
}
39+
return [...realmRoles, ...appRoles]
40+
}
8141

82-
/**
83-
* @function
84-
* @public
85-
*
86-
* Extract content out of token.
87-
* The content is the middle part.
88-
*
89-
* @returns {Object} The token its content
90-
*/
91-
function getContent () {
92-
return JSON.parse(Buffer.from(tkn.split('.')[1], 'base64').toString())
93-
}
42+
/**
43+
* @function
44+
* @private
45+
*
46+
* Get expiration out of token content.
47+
*
48+
* @param {number} [exp] The `expiration` timestamp in seconds
49+
* @param {number} [iat] The `issued at` timestamp in seconds
50+
* @returns {number} The expiration delta in milliseconds
51+
*/
52+
function getExpiration ({ exp = 60, iat = 0 }) {
53+
return (exp - iat) * 1000
54+
}
9455

95-
/**
96-
* @function
97-
* @public
98-
*
99-
* Get various data out of token content.
100-
* Get the current scope of the user and
101-
* when the token expires.
102-
*
103-
* @returns {Object} The extracted data
104-
*/
105-
function getData (userInfoFields) {
106-
const content = getContent()
56+
/**
57+
* @function
58+
* @private
59+
*
60+
* Get necessary user information out of token content.
61+
*
62+
* @param {Object} content The token its content
63+
* @param {Array.<?string>} [fields] The necessary fields
64+
* @returns {Object} The collection of requested user info
65+
*/
66+
function getUserInfo (content, fields = []) {
67+
return _.pick(content, ['sub', ...fields])
68+
}
10769

108-
return {
109-
expiresIn: getExpiration(content),
110-
credentials: Object.assign({
111-
scope: getScope(content)
112-
}, getUserInfo(content, userInfoFields))
113-
}
114-
}
70+
/**
71+
* @function
72+
* @public
73+
*
74+
* Extract content out of token.
75+
* The content is the middle part.
76+
*
77+
* @param {string} tkn The token to be checked
78+
* @returns {Object} The token its content
79+
*/
80+
function getContent (tkn) {
81+
return JSON.parse(Buffer.from(tkn.split('.')[1], 'base64').toString())
82+
}
11583

116-
/**
117-
* @function
118-
* @public
119-
*
120-
* Get the original token.
121-
*
122-
* @returns {string} The original token
123-
*/
124-
function get () {
125-
return tkn
84+
/**
85+
* @function
86+
* @public
87+
*
88+
* Get various data out of token content.
89+
* Get the current scope of the user and
90+
* when the token expires.
91+
*
92+
* @param {string} tkn The token to be checked
93+
* @returns {Object} The extracted data
94+
*/
95+
function getData (tkn, userInfoFields) {
96+
const content = getContent(tkn)
97+
98+
return {
99+
expiresIn: getExpiration(content),
100+
credentials: Object.assign({
101+
scope: getScope(content)
102+
}, getUserInfo(content, userInfoFields))
126103
}
104+
}
127105

128-
/**
129-
* @function
130-
* @private
131-
*
132-
* Initialize token instance.
133-
*
134-
* @returns {Object|false} The token instance or `false` dependent on field
135-
*/
136-
function init () {
137-
const match = extractToken(field)
138-
139-
if (!match) {
140-
return false
141-
}
142-
143-
tkn = match[1]
144-
145-
return {
146-
getContent,
147-
getData,
148-
get
149-
}
150-
}
106+
/**
107+
* @function
108+
* @public
109+
*
110+
* Get token out of header field.
111+
*
112+
* @param {string} field The header field to be scanned
113+
* @returns {string|false} The token or `false` dependent on field
114+
*/
115+
function create (field) {
116+
const match = extractToken(field)
151117

152-
return init()
118+
return match ? match[1] : false
153119
}
154120

155-
module.exports = token
121+
module.exports = {
122+
create,
123+
getContent,
124+
getData
125+
}

0 commit comments

Comments
 (0)