-
Notifications
You must be signed in to change notification settings - Fork 17
/
index.js
93 lines (86 loc) · 2.97 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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
const BbPromise = require('bluebird');
const jwt = require('jsonwebtoken');
const request = require('request');
const _ = require('lodash');
const getPem = require('rsa-pem-from-mod-exp');
const publicKeys = {};
// Validate the jwt Token with the audience and the issuer
const verifyJwt = function verifyJwt(jwtToken, publicKey, aud, iss) {
return new BbPromise(function (resolve, reject) {
jwt.verify(jwtToken, publicKey, { algorithms: ['RS256'], audience: aud, issuer: iss },
function (error, decoded) {
if (!error) {
resolve(decoded);
} else {
reject(error);
}
});
});
};
// fetch publicKeys (mod and exp) from jwks_uri if there are no current kid matching
const getPublicKeys = function getPublicKeys(JWK_URI, jwtKid) {
if (hasPublicKey(jwtKid)) {
return new BbPromise(function (resolve, reject) {
resolve(publicKeys);
});
} else {
return new BbPromise(function (resolve, reject) {
request(JWK_URI, function (error, response, body) {
if (!error && response.statusCode == 200) {
let keys = JSON.parse(body).keys;
updatePublicKeys(keys);
resolve(publicKeys);
} else {
reject(error)
}
});
});
}
};
// generate and cache the rsa public key from modulus exponent
const updatePublicKeys = function (b2cKeys) {
_.forEach(b2cKeys, function (value) {
publicKeys[value.kid] = getPem(value.n, value.e)
});
};
// retunrs the public key for the given kid from the cached keys
const getPublicKey = function (jwtKid) {
if (publicKeys.hasOwnProperty(jwtKid)) {
return publicKeys[jwtKid];
} else {
return false;
}
};
// check if the kid has a public key
const hasPublicKey = function (jwtKid) {
return publicKeys.hasOwnProperty(jwtKid);
};
// verify the jwtToken against the given configuration
exports.verify = function (jwtToken, config) {
return new BbPromise(function (resolve, reject) {
let decoded = jwt.decode(jwtToken, { complete: true });
if (!decoded) {
reject('{ "status":"error", "message":"Error Decoding JWT Token" }');
} else {
let jwtKid = decoded.header.kid;
if (!jwtKid) {
reject('{ "status":"error", "message":"Invalid JWT Token" }');
} else {
getPublicKeys(config.JWK_URI, jwtKid).then(function (response) {
if (hasPublicKey(jwtKid)) {
let publicKey = getPublicKey(jwtKid);
return verifyJwt(jwtToken, publicKey, config.AUD, config.ISS).then(function (response) {
resolve(JSON.stringify({ "status": "success", "message": response }));
}).catch(function (error) {
reject(JSON.stringify({ "status": "error", "message": error }));
});
} else {
reject('{ "status":"error", "message":"Invalid jwt kid" }');
}
}).catch(function (error) {
reject('{ "status":"error", "message":"Cannot fetch data from JWK_URI" }');
})
}
}
});
};