@axa-fr/react-oidc 6.3.1 → 6.5.0-beta0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/OidcServiceWorker.js +61 -8
- package/dist/ReactOidc.d.ts +1 -1
- package/dist/ReactOidc.js +4 -3
- package/dist/ReactOidc.js.map +1 -1
- package/dist/vanilla/initSession.d.ts +4 -0
- package/dist/vanilla/initSession.d.ts.map +1 -1
- package/dist/vanilla/initSession.js +23 -1
- package/dist/vanilla/initSession.js.map +1 -1
- package/dist/vanilla/initWorker.d.ts +4 -0
- package/dist/vanilla/initWorker.d.ts.map +1 -1
- package/dist/vanilla/initWorker.js +14 -1
- package/dist/vanilla/initWorker.js.map +1 -1
- package/dist/vanilla/oidc.d.ts +4 -3
- package/dist/vanilla/oidc.d.ts.map +1 -1
- package/dist/vanilla/oidc.js +153 -76
- package/dist/vanilla/oidc.js.map +1 -1
- package/dist/vanilla/parseTokens.d.ts +1 -0
- package/dist/vanilla/parseTokens.d.ts.map +1 -1
- package/dist/vanilla/parseTokens.js +31 -2
- package/dist/vanilla/parseTokens.js.map +1 -1
- package/package.json +1 -1
- package/src/oidc/ReactOidc.tsx +3 -3
- package/src/oidc/vanilla/OidcServiceWorker.js +61 -8
- package/src/oidc/vanilla/initSession.ts +23 -2
- package/src/oidc/vanilla/initWorker.ts +12 -0
- package/src/oidc/vanilla/oidc.ts +93 -26
- package/src/oidc/vanilla/parseTokens.ts +33 -1
|
@@ -2,4 +2,5 @@ export declare const setTokens: (tokens: any) => any;
|
|
|
2
2
|
export declare const parseOriginalTokens: (tokens: any) => any;
|
|
3
3
|
export declare const computeTimeLeft: (refreshTimeBeforeTokensExpirationInSecond: any, expiresAt: any) => number;
|
|
4
4
|
export declare const isTokensValid: (tokens: any) => boolean;
|
|
5
|
+
export declare const isTokensOidcValid: (tokens: any, nonce: any, oidcServerConfiguration: any) => boolean;
|
|
5
6
|
//# sourceMappingURL=parseTokens.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseTokens.d.ts","sourceRoot":"","sources":["../../src/oidc/vanilla/parseTokens.ts"],"names":[],"mappings":"AAmCA,eAAO,MAAM,SAAS,sBAyBrB,CAAA;
|
|
1
|
+
{"version":3,"file":"parseTokens.d.ts","sourceRoot":"","sources":["../../src/oidc/vanilla/parseTokens.ts"],"names":[],"mappings":"AAmCA,eAAO,MAAM,SAAS,sBAyBrB,CAAA;AAID,eAAO,MAAM,mBAAmB,sBA+B/B,CAAA;AAED,eAAO,MAAM,eAAe,4EAG3B,CAAA;AAED,eAAO,MAAM,aAAa,0BAKzB,CAAA;AAID,eAAO,MAAM,iBAAiB,oEA2B7B,CAAA"}
|
|
@@ -11,7 +11,7 @@ var __assign = (this && this.__assign) || function () {
|
|
|
11
11
|
return __assign.apply(this, arguments);
|
|
12
12
|
};
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.isTokensValid = exports.computeTimeLeft = exports.parseOriginalTokens = exports.setTokens = void 0;
|
|
14
|
+
exports.isTokensOidcValid = exports.isTokensValid = exports.computeTimeLeft = exports.parseOriginalTokens = exports.setTokens = void 0;
|
|
15
15
|
var idTokenPayload = function (token) {
|
|
16
16
|
if (!token) {
|
|
17
17
|
return null;
|
|
@@ -57,7 +57,7 @@ var setTokens = function (tokens) {
|
|
|
57
57
|
else {
|
|
58
58
|
accessTokenPayload = extractAccessTokenPayload(tokens);
|
|
59
59
|
}
|
|
60
|
-
var _idTokenPayload = idTokenPayload(tokens.idToken);
|
|
60
|
+
var _idTokenPayload = tokens.idTokenPayload ? tokens.idTokenPayload : idTokenPayload(tokens.idToken);
|
|
61
61
|
var idTokenExipreAt = (_idTokenPayload && _idTokenPayload.exp) ? _idTokenPayload.exp : Number.MAX_VALUE;
|
|
62
62
|
var accessTokenExpiresAt = (accessTokenPayload && accessTokenPayload.exp) ? accessTokenPayload.exp : tokens.issuedAt + tokens.expiresIn;
|
|
63
63
|
var expiresAt = idTokenExipreAt < accessTokenExpiresAt ? idTokenExipreAt : accessTokenExpiresAt;
|
|
@@ -104,4 +104,33 @@ var isTokensValid = function (tokens) {
|
|
|
104
104
|
return (0, exports.computeTimeLeft)(0, tokens.expiresAt) > 0;
|
|
105
105
|
};
|
|
106
106
|
exports.isTokensValid = isTokensValid;
|
|
107
|
+
// https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation (excluding rules #1, #4, #5, #7, #8, #12, and #13 which did not apply).
|
|
108
|
+
// https://github.com/openid/AppAuth-JS/issues/65
|
|
109
|
+
var isTokensOidcValid = function (tokens, nonce, oidcServerConfiguration) {
|
|
110
|
+
if (tokens.idTokenPayload) {
|
|
111
|
+
var idTokenPayload_1 = tokens.idTokenPayload;
|
|
112
|
+
// 2: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery) MUST exactly match the value of the iss (issuer) Claim.
|
|
113
|
+
if (oidcServerConfiguration.issuer !== idTokenPayload_1.iss) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
// 3: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience. The aud (audience) Claim MAY contain an array with more than one element. The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences not trusted by the Client.
|
|
117
|
+
// 6: If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer.
|
|
118
|
+
// 9: The current time MUST be before the time represented by the exp Claim.
|
|
119
|
+
var currentTimeUnixSecond = new Date().getTime() / 1000;
|
|
120
|
+
if (idTokenPayload_1.exp && idTokenPayload_1.exp < currentTimeUnixSecond) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
// 10: The iat Claim can be used to reject tokens that were issued too far away from the current time, limiting the amount of time that nonces need to be stored to prevent attacks. The acceptable range is Client specific.
|
|
124
|
+
var timeInSevenDays = 60 * 60 * 24 * 7;
|
|
125
|
+
if (idTokenPayload_1.iat && (idTokenPayload_1.iat + timeInSevenDays) < currentTimeUnixSecond) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
// 11: If a nonce value was sent in the Authentication Request, a nonce Claim MUST be present and its value checked to verify that it is the same value as the one that was sent in the Authentication Request. The Client SHOULD check the nonce value for replay attacks. The precise method for detecting replay attacks is Client specific.
|
|
129
|
+
if (idTokenPayload_1.nonce && idTokenPayload_1.nonce !== nonce) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
};
|
|
135
|
+
exports.isTokensOidcValid = isTokensOidcValid;
|
|
107
136
|
//# sourceMappingURL=parseTokens.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseTokens.js","sourceRoot":"","sources":["../../src/oidc/vanilla/parseTokens.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,IAAM,cAAc,GAAG,UAAC,KAAK;IACzB,IAAG,CAAC,KAAK,EAAC;QACN,OAAO,IAAI,CAAC;KACf;IACD,IAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,IAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/D,IAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC;QACzE,OAAO,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;AACnC,CAAC,CAAA;AAED,IAAM,WAAW,GAAG,UAAC,GAAG,EAAE,IAAI;IAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AACxC,CAAC,CAAA;AAED,IAAM,yBAAyB,GAAG,UAAA,MAAM;IACpC,IAAG,MAAM,CAAC,kBAAkB,EAC5B;QACI,OAAO,MAAM,CAAC,kBAAkB,CAAC;KACpC;IACD,IAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IACvC,IAAG;QACC,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,WAAW,EAAC,GAAG,CAAC,KAAK,CAAC,EAAE;YACpD,OAAO,IAAI,CAAC;SACf;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KACtD;IAAC,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACnB;IACD,OAAO,IAAI,CAAC;AAChB,CAAC,CAAC;AAGK,IAAM,SAAS,GAAG,UAAC,MAAM;IAE5B,IAAG,CAAC,MAAM,EAAC;QACP,OAAO,IAAI,CAAC;KACf;IACD,IAAI,kBAAkB,CAAC;IAEvB,IAAG,CAAC,MAAM,CAAC,QAAQ,EAAE;QACjB,IAAM,qBAAqB,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAE,IAAI,CAAC;QACzD,MAAM,CAAC,QAAQ,GAAG,qBAAqB,CAAC;KAC3C;IAED,IAAG,MAAM,CAAC,kBAAkB,KAAK,SAAS,EAAE;QACxC,kBAAkB,GAAG,MAAM,CAAC,kBAAkB,CAAC;KAClD;SACI;QACD,kBAAkB,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;KAC1D;IACD,IAAM,eAAe,GAAG,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"parseTokens.js","sourceRoot":"","sources":["../../src/oidc/vanilla/parseTokens.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/oidc/ReactOidc.tsx
CHANGED
|
@@ -21,7 +21,7 @@ export const useOidc =(configurationName=defaultConfigurationName) =>{
|
|
|
21
21
|
const oidc = getOidc(configurationName);
|
|
22
22
|
setIsAuthenticated(defaultIsAuthenticated(getOidc, configurationName));
|
|
23
23
|
const newSubscriptionId = oidc.subscriveEvents((name, data) => {
|
|
24
|
-
if(name === Oidc.eventNames.logout_from_another_tab || name === Oidc.eventNames.logout_from_same_tab){
|
|
24
|
+
if(name === Oidc.eventNames.logout_from_another_tab || name === Oidc.eventNames.logout_from_same_tab || name === Oidc.eventNames.token_aquired){
|
|
25
25
|
if(isMounted) {
|
|
26
26
|
setIsAuthenticated(defaultIsAuthenticated(getOidc, configurationName));
|
|
27
27
|
}
|
|
@@ -33,8 +33,8 @@ export const useOidc =(configurationName=defaultConfigurationName) =>{
|
|
|
33
33
|
};
|
|
34
34
|
}, [configurationName]);
|
|
35
35
|
|
|
36
|
-
const login = (callbackPath:string | undefined = undefined, extras:StringMap=null, state: string|undefined=undefined) => {
|
|
37
|
-
return getOidc(configurationName).loginAsync(callbackPath, extras, state);
|
|
36
|
+
const login = (callbackPath:string | undefined = undefined, extras:StringMap=null, state: string|undefined=undefined, silentLoginOnly = false) => {
|
|
37
|
+
return getOidc(configurationName).loginAsync(callbackPath, extras, state, false, undefined, silentLoginOnly);
|
|
38
38
|
};
|
|
39
39
|
const logout = (callbackPath: string | null | undefined = undefined, extras:StringMap=null) => {
|
|
40
40
|
return getOidc(configurationName).logoutAsync(callbackPath, extras);
|
|
@@ -20,6 +20,7 @@ let database = {
|
|
|
20
20
|
tokens: null,
|
|
21
21
|
status:null,
|
|
22
22
|
items:[],
|
|
23
|
+
nonce: null,
|
|
23
24
|
oidcServerConfiguration: null
|
|
24
25
|
}
|
|
25
26
|
};
|
|
@@ -56,6 +57,37 @@ const isTokensValid= (tokens) =>{
|
|
|
56
57
|
return computeTimeLeft(0, tokens.expiresAt) > 0;
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
// https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation (excluding rules #1, #4, #5, #7, #8, #12, and #13 which did not apply).
|
|
61
|
+
// https://github.com/openid/AppAuth-JS/issues/65
|
|
62
|
+
const isTokensOidcValid =(tokens, nonce, oidcServerConfiguration) =>{
|
|
63
|
+
if(tokens.idTokenPayload) {
|
|
64
|
+
const idTokenPayload = tokens.idTokenPayload;
|
|
65
|
+
// 2: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery) MUST exactly match the value of the iss (issuer) Claim.
|
|
66
|
+
if(oidcServerConfiguration.issuer !== idTokenPayload.iss){
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
// 3: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience. The aud (audience) Claim MAY contain an array with more than one element. The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences not trusted by the Client.
|
|
70
|
+
|
|
71
|
+
// 6: If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer.
|
|
72
|
+
|
|
73
|
+
// 9: The current time MUST be before the time represented by the exp Claim.
|
|
74
|
+
const currentTimeUnixSecond = new Date().getTime() /1000;
|
|
75
|
+
if(idTokenPayload.exp && idTokenPayload.exp < currentTimeUnixSecond) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
// 10: The iat Claim can be used to reject tokens that were issued too far away from the current time, limiting the amount of time that nonces need to be stored to prevent attacks. The acceptable range is Client specific.
|
|
79
|
+
const timeInSevenDays = 60 * 60 * 24 * 7;
|
|
80
|
+
if(idTokenPayload.iat && (idTokenPayload.iat + timeInSevenDays) < currentTimeUnixSecond) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
// 11: If a nonce value was sent in the Authentication Request, a nonce Claim MUST be present and its value checked to verify that it is the same value as the one that was sent in the Authentication Request. The Client SHOULD check the nonce value for replay attacks. The precise method for detecting replay attacks is Client specific.
|
|
84
|
+
if (idTokenPayload.nonce && idTokenPayload.nonce !== nonce) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
59
91
|
function hideTokens(currentDatabaseElement) {
|
|
60
92
|
const configurationName = currentDatabaseElement.configurationName;
|
|
61
93
|
return (response) => {
|
|
@@ -79,8 +111,12 @@ function hideTokens(currentDatabaseElement) {
|
|
|
79
111
|
let _idTokenPayload = null;
|
|
80
112
|
if(tokens.id_token) {
|
|
81
113
|
_idTokenPayload = extractTokenPayload(tokens.id_token);
|
|
114
|
+
tokens.idTokenPayload = {..._idTokenPayload};
|
|
115
|
+
if(_idTokenPayload.nonce) {
|
|
116
|
+
const keyNonce = NONCE_TOKEN + '_'+ currentDatabaseElement.configurationName;
|
|
117
|
+
_idTokenPayload.nonce = keyNonce;
|
|
118
|
+
}
|
|
82
119
|
secureTokens.idTokenPayload = _idTokenPayload;
|
|
83
|
-
tokens.idTokenPayload = _idTokenPayload;
|
|
84
120
|
}
|
|
85
121
|
if(tokens.refresh_token){
|
|
86
122
|
secureTokens.refresh_token = REFRESH_TOKEN + "_" + configurationName;
|
|
@@ -92,6 +128,10 @@ function hideTokens(currentDatabaseElement) {
|
|
|
92
128
|
secureTokens.expiresAt = expiresAt;
|
|
93
129
|
const body = JSON.stringify(secureTokens);
|
|
94
130
|
tokens.expiresAt = expiresAt;
|
|
131
|
+
|
|
132
|
+
if(!isTokensOidcValid(tokens, currentDatabaseElement.nonce.nonce, currentDatabaseElement.oidcServerConfiguration)){
|
|
133
|
+
throw Error("Tokens are not OpenID valid");
|
|
134
|
+
}
|
|
95
135
|
currentDatabaseElement.tokens = tokens;
|
|
96
136
|
currentDatabaseElement.status = "LOGGED_IN";
|
|
97
137
|
return new Response(body, response);
|
|
@@ -138,7 +178,7 @@ const getCurrentDatabaseDomain = (database, url) => {
|
|
|
138
178
|
}
|
|
139
179
|
}
|
|
140
180
|
|
|
141
|
-
if(hasToSendToken){
|
|
181
|
+
if(hasToSendToken) {
|
|
142
182
|
if(!currentDatabase.tokens) {
|
|
143
183
|
return null;
|
|
144
184
|
}
|
|
@@ -159,6 +199,7 @@ const serializeHeaders = (headers) => {
|
|
|
159
199
|
|
|
160
200
|
const REFRESH_TOKEN = 'REFRESH_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER';
|
|
161
201
|
const ACCESS_TOKEN = 'ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER';
|
|
202
|
+
const NONCE_TOKEN = 'NONCE_SECURED_BY_OIDC_SERVICE_WORKER';
|
|
162
203
|
|
|
163
204
|
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
164
205
|
|
|
@@ -215,11 +256,14 @@ const handleFetch = async (event) => {
|
|
|
215
256
|
let newBody = actualBody;
|
|
216
257
|
for(let i= 0;i<numberDatabase;i++){
|
|
217
258
|
const currentDb = currentDatabases[i];
|
|
218
|
-
|
|
219
|
-
if(currentDb && currentDb.tokens != null
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
259
|
+
|
|
260
|
+
if(currentDb && currentDb.tokens != null) {
|
|
261
|
+
const keyRefreshToken = REFRESH_TOKEN + '_'+ currentDb.configurationName;
|
|
262
|
+
if(actualBody.includes(keyRefreshToken)) {
|
|
263
|
+
newBody = newBody.replace(keyRefreshToken, encodeURIComponent(currentDb.tokens.refresh_token));
|
|
264
|
+
currentDatabase = currentDb;
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
223
267
|
}
|
|
224
268
|
}
|
|
225
269
|
|
|
@@ -327,6 +371,8 @@ addEventListener('message', event => {
|
|
|
327
371
|
checkDomain(domains, tokenEndpoint);
|
|
328
372
|
const userInfoEndpoint = oidcServerConfiguration.userInfoEndpoint;
|
|
329
373
|
checkDomain(domains, userInfoEndpoint);
|
|
374
|
+
const issuer = oidcServerConfiguration.issuer;
|
|
375
|
+
checkDomain(domains, issuer);
|
|
330
376
|
currentDatabase.oidcServerConfiguration = oidcServerConfiguration;
|
|
331
377
|
const where = data.data.where;
|
|
332
378
|
if(where === "loginCallbackAsync" || where === "tryKeepExistingSessionAsync") {
|
|
@@ -348,6 +394,9 @@ addEventListener('message', event => {
|
|
|
348
394
|
if(tokens.refresh_token){
|
|
349
395
|
tokens.refresh_token = REFRESH_TOKEN + "_" + configurationName;
|
|
350
396
|
}
|
|
397
|
+
if(tokens.idTokenPayload && tokens.idTokenPayload.nonce){
|
|
398
|
+
tokens.idTokenPayload.nonce = NONCE_TOKEN + "_" + configurationName;
|
|
399
|
+
}
|
|
351
400
|
port.postMessage({
|
|
352
401
|
tokens,
|
|
353
402
|
status: currentDatabase.status,
|
|
@@ -364,8 +413,12 @@ addEventListener('message', event => {
|
|
|
364
413
|
const sessionState = currentDatabase.sessionState;
|
|
365
414
|
port.postMessage({configurationName, sessionState});
|
|
366
415
|
return;
|
|
416
|
+
case "setNonce":
|
|
417
|
+
currentDatabase.nonce = data.data.nonce;
|
|
418
|
+
port.postMessage({configurationName});
|
|
419
|
+
return;
|
|
367
420
|
default:
|
|
368
|
-
currentDatabase.items = data.data;
|
|
421
|
+
currentDatabase.items = { ...data.data };
|
|
369
422
|
port.postMessage({configurationName});
|
|
370
423
|
return;
|
|
371
424
|
}
|
|
@@ -35,13 +35,34 @@
|
|
|
35
35
|
return storage[`oidc.session_state.${configurationName}:${redirectUri}`];
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
const setNonceAsync = (nonce) => {
|
|
39
|
+
localStorage[`oidc.nonce.${configurationName}:${redirectUri}`] = nonce.nonce;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const getNonceAsync= async () => {
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
const result = {nonce: localStorage[`oidc.nonce.${configurationName}:${redirectUri}`]};
|
|
45
|
+
localStorage[`oidc.nonce.${configurationName}:${redirectUri}`] = "";
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
38
49
|
const getTokens = () => {
|
|
39
|
-
|
|
40
50
|
if(!storage[`oidc.${configurationName}:${redirectUri}`]){
|
|
41
51
|
return null;
|
|
42
52
|
}
|
|
43
53
|
return JSON.stringify({ tokens : JSON.parse(storage[`oidc.${configurationName}:${redirectUri}`]).tokens });
|
|
44
54
|
}
|
|
45
55
|
|
|
46
|
-
return {
|
|
56
|
+
return {
|
|
57
|
+
saveItemsAsync,
|
|
58
|
+
loadItemsAsync,
|
|
59
|
+
clearAsync,
|
|
60
|
+
initAsync,
|
|
61
|
+
setTokens,
|
|
62
|
+
getTokens,
|
|
63
|
+
setSessionState,
|
|
64
|
+
getSessionState,
|
|
65
|
+
setNonceAsync,
|
|
66
|
+
getNonceAsync
|
|
67
|
+
};
|
|
47
68
|
}
|
|
@@ -138,6 +138,16 @@ export const initWorkerAsync = async(serviceWorkerRelativeUrl, configurationName
|
|
|
138
138
|
return result.sessionState;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
const setNonceAsync = (nonce) => {
|
|
142
|
+
return sendMessageAsync(registration)({type: "setNonce", data: {nonce}, configurationName});
|
|
143
|
+
}
|
|
144
|
+
const NONCE_TOKEN = 'NONCE_SECURED_BY_OIDC_SERVICE_WORKER';
|
|
145
|
+
const getNonceAsync= async () => {
|
|
146
|
+
// @ts-ignore
|
|
147
|
+
const keyNonce = NONCE_TOKEN + '_'+ configurationName;
|
|
148
|
+
return {nonce:keyNonce};
|
|
149
|
+
}
|
|
150
|
+
|
|
141
151
|
return {
|
|
142
152
|
saveItemsAsync,
|
|
143
153
|
loadItemsAsync,
|
|
@@ -148,6 +158,8 @@ export const initWorkerAsync = async(serviceWorkerRelativeUrl, configurationName
|
|
|
148
158
|
isServiceWorkerProxyActiveAsync,
|
|
149
159
|
setSessionStateAsync,
|
|
150
160
|
getSessionStateAsync,
|
|
161
|
+
setNonceAsync,
|
|
162
|
+
getNonceAsync,
|
|
151
163
|
unregisterAsync,
|
|
152
164
|
};
|
|
153
165
|
}
|
package/src/oidc/vanilla/oidc.ts
CHANGED
|
@@ -19,7 +19,7 @@ import timer from './timer';
|
|
|
19
19
|
import {CheckSessionIFrame} from "./checkSessionIFrame"
|
|
20
20
|
import {getParseQueryStringFromLocation} from "./route-utils";
|
|
21
21
|
import {AuthorizationServiceConfigurationJson} from "@openid/appauth/src/authorization_service_configuration";
|
|
22
|
-
import {computeTimeLeft, isTokensValid, parseOriginalTokens, setTokens} from "./parseTokens";
|
|
22
|
+
import {computeTimeLeft, isTokensOidcValid, isTokensValid, parseOriginalTokens, setTokens} from "./parseTokens";
|
|
23
23
|
|
|
24
24
|
const performTokenRequestAsync= async (url, details, extras) => {
|
|
25
25
|
|
|
@@ -80,10 +80,12 @@ const internalFetch = async (url, headers, numberRetry=0) => {
|
|
|
80
80
|
|
|
81
81
|
export interface OidcAuthorizationServiceConfigurationJson extends AuthorizationServiceConfigurationJson{
|
|
82
82
|
check_session_iframe?: string;
|
|
83
|
+
issuer:string;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
export class OidcAuthorizationServiceConfiguration extends AuthorizationServiceConfiguration{
|
|
86
87
|
private check_session_iframe: string;
|
|
88
|
+
private issuer: string;
|
|
87
89
|
|
|
88
90
|
constructor(request: any) {
|
|
89
91
|
super(request);
|
|
@@ -92,6 +94,7 @@ export class OidcAuthorizationServiceConfiguration extends AuthorizationServiceC
|
|
|
92
94
|
this.revocationEndpoint = request.revocation_endpoint;
|
|
93
95
|
this.userInfoEndpoint = request.userinfo_endpoint;
|
|
94
96
|
this.check_session_iframe = request.check_session_iframe;
|
|
97
|
+
this.issuer = request.issuer;
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
}
|
|
@@ -113,6 +116,7 @@ export interface AuthorityConfiguration {
|
|
|
113
116
|
end_session_endpoint?: string;
|
|
114
117
|
userinfo_endpoint?: string;
|
|
115
118
|
check_session_iframe?:string;
|
|
119
|
+
issuer:string;
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
export type OidcConfiguration = {
|
|
@@ -153,9 +157,12 @@ const loginCallbackWithAutoTokensRenewAsync = async (oidc) => {
|
|
|
153
157
|
async function renewTokensAndStartTimerAsync(oidc, refreshToken, forceRefresh =false) {
|
|
154
158
|
const {tokens, status} = await oidc.synchroniseTokensAsync(refreshToken, 0, forceRefresh);
|
|
155
159
|
oidc.tokens = tokens;
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
const serviceWorker = await initWorkerAsync(oidc.configuration.service_worker_relative_url, oidc.configurationName);
|
|
161
|
+
if (!serviceWorker) {
|
|
162
|
+
const session = initSession(this.configurationName, oidc.configuration.redirect_uri, oidc.configuration.storage);
|
|
163
|
+
await session.setTokens(oidc.tokens);
|
|
158
164
|
}
|
|
165
|
+
|
|
159
166
|
if (!oidc.tokens) {
|
|
160
167
|
await oidc.destroyAsync(status);
|
|
161
168
|
return;
|
|
@@ -321,9 +328,9 @@ export class Oidc {
|
|
|
321
328
|
public tokens: null;
|
|
322
329
|
public events: Array<any>;
|
|
323
330
|
private timeoutId: NodeJS.Timeout;
|
|
324
|
-
private serviceWorker?: any;
|
|
331
|
+
//private serviceWorker?: any;
|
|
325
332
|
private configurationName: string;
|
|
326
|
-
private session?: any;
|
|
333
|
+
//private session?: any;
|
|
327
334
|
private checkSessionIFrame: CheckSessionIFrame;
|
|
328
335
|
constructor(configuration:OidcConfiguration, configurationName="default") {
|
|
329
336
|
let silent_login_uri = configuration.silent_login_uri;
|
|
@@ -342,8 +349,8 @@ export class Oidc {
|
|
|
342
349
|
this.userInfo = null;
|
|
343
350
|
this.events = [];
|
|
344
351
|
this.timeoutId = null;
|
|
345
|
-
this.serviceWorker = null;
|
|
346
|
-
this.session = null;
|
|
352
|
+
//this.serviceWorker = null;
|
|
353
|
+
//this.session = null;
|
|
347
354
|
this.synchroniseTokensAsync.bind(this);
|
|
348
355
|
this.loginCallbackWithAutoTokensRenewAsync.bind(this);
|
|
349
356
|
this.initAsync.bind(this);
|
|
@@ -519,6 +526,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
519
526
|
token_endpoint: authorityConfiguration.token_endpoint,
|
|
520
527
|
userinfo_endpoint: authorityConfiguration.userinfo_endpoint,
|
|
521
528
|
check_session_iframe: authorityConfiguration.check_session_iframe,
|
|
529
|
+
issuer: authorityConfiguration.issuer,
|
|
522
530
|
});
|
|
523
531
|
}
|
|
524
532
|
|
|
@@ -555,7 +563,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
555
563
|
serviceWorker.startKeepAliveServiceWorker();
|
|
556
564
|
// @ts-ignore
|
|
557
565
|
this.tokens = tokens;
|
|
558
|
-
this.serviceWorker = serviceWorker;
|
|
566
|
+
//this.serviceWorker = serviceWorker;
|
|
559
567
|
// @ts-ignore
|
|
560
568
|
this.timeoutId = autoRenewTokens(this, this.tokens.refreshToken, this.tokens.expiresAt);
|
|
561
569
|
const sessionState = await serviceWorker.getSessionStateAsync();
|
|
@@ -583,7 +591,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
583
591
|
// @ts-ignore
|
|
584
592
|
this.tokens = setTokens(tokens);
|
|
585
593
|
//session.setTokens(this.tokens);
|
|
586
|
-
this.session = session;
|
|
594
|
+
//this.session = session;
|
|
587
595
|
// @ts-ignore
|
|
588
596
|
this.timeoutId = autoRenewTokens(this, tokens.refreshToken, this.tokens.expiresAt);
|
|
589
597
|
const sessionState = session.getSessionState();
|
|
@@ -619,40 +627,76 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
619
627
|
}
|
|
620
628
|
|
|
621
629
|
loginPromise: Promise<any>=null;
|
|
622
|
-
async loginAsync(callbackPath:string=undefined, extras:StringMap=null, state:string=undefined, isSilentSignin:boolean=false, scope:string=undefined) {
|
|
630
|
+
async loginAsync(callbackPath:string=undefined, extras:StringMap=null, state:string=undefined, isSilentSignin:boolean=false, scope:string=undefined, silentLoginOnly = false) {
|
|
623
631
|
if(this.loginPromise !== null){
|
|
624
632
|
return this.loginPromise;
|
|
625
633
|
}
|
|
626
634
|
|
|
627
635
|
const loginLocalAsync=async () => {
|
|
628
|
-
|
|
636
|
+
|
|
629
637
|
const location = window.location;
|
|
630
638
|
const url = callbackPath || location.pathname + (location.search || '') + (location.hash || '');
|
|
631
|
-
|
|
639
|
+
|
|
632
640
|
const configuration = this.configuration;
|
|
633
641
|
|
|
642
|
+
if(silentLoginOnly){
|
|
643
|
+
try {
|
|
644
|
+
const extraFinal = extras ?? configuration.extras ?? {};
|
|
645
|
+
const silentResult = await this.silentLoginAsync({
|
|
646
|
+
...extraFinal,
|
|
647
|
+
prompt: "none"
|
|
648
|
+
}, state, scope);
|
|
649
|
+
|
|
650
|
+
if (silentResult) {
|
|
651
|
+
this.tokens = silentResult.tokens;
|
|
652
|
+
this.publishEvent(eventNames.token_aquired, {});
|
|
653
|
+
// @ts-ignore
|
|
654
|
+
this.timeoutId = autoRenewTokens(this, this.tokens.refreshToken, this.tokens.expiresAt);
|
|
655
|
+
return {};
|
|
656
|
+
}
|
|
657
|
+
}catch (e) {
|
|
658
|
+
return e;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
this.publishEvent(eventNames.loginAsync_begin, {});
|
|
662
|
+
try {
|
|
634
663
|
const redirectUri = isSilentSignin ? configuration.silent_redirect_uri : configuration.redirect_uri;
|
|
635
664
|
if (!scope) {
|
|
636
665
|
scope = configuration.scope;
|
|
637
666
|
}
|
|
638
667
|
|
|
668
|
+
const randomString = function(length) {
|
|
669
|
+
let text = "";
|
|
670
|
+
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
671
|
+
for(let i = 0; i < length; i++) {
|
|
672
|
+
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
|
673
|
+
}
|
|
674
|
+
return text;
|
|
675
|
+
}
|
|
676
|
+
|
|
639
677
|
setLoginParams(this.configurationName, redirectUri, {callbackPath: url, extras, state});
|
|
640
|
-
|
|
678
|
+
const extraFinal = extras ?? configuration.extras ?? {};
|
|
679
|
+
if(!extraFinal.nonce) {
|
|
680
|
+
extraFinal["nonce"] = randomString(12);
|
|
681
|
+
}
|
|
682
|
+
const nonce = {"nonce":extraFinal.nonce};
|
|
641
683
|
let serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
|
|
642
684
|
const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
|
|
643
685
|
let storage;
|
|
644
686
|
if (serviceWorker) {
|
|
645
687
|
serviceWorker.startKeepAliveServiceWorker();
|
|
646
688
|
await serviceWorker.initAsync(oidcServerConfiguration, "loginAsync");
|
|
689
|
+
await serviceWorker.setNonceAsync(nonce);
|
|
647
690
|
storage = new MemoryStorageBackend(serviceWorker.saveItemsAsync, {});
|
|
648
691
|
await storage.setItem("dummy", {});
|
|
692
|
+
|
|
649
693
|
} else {
|
|
650
694
|
const session = initSession(this.configurationName, redirectUri);
|
|
695
|
+
await session.setNonceAsync(nonce);
|
|
651
696
|
storage = new MemoryStorageBackend(session.saveItemsAsync, {});
|
|
652
697
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
698
|
+
|
|
699
|
+
|
|
656
700
|
// @ts-ignore
|
|
657
701
|
const queryStringUtil = redirectUri.includes("#") ? new HashQueryStringUtils() : new NoHashQueryStringUtils();
|
|
658
702
|
const authorizationHandler = new RedirectRequestHandler(storage, queryStringUtil, window.location, new DefaultCrypto());
|
|
@@ -746,9 +790,13 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
746
790
|
const tokens = response.tokens;
|
|
747
791
|
const parsedTokens = setTokens(tokens);
|
|
748
792
|
this.tokens = parsedTokens;
|
|
749
|
-
|
|
750
|
-
|
|
793
|
+
const oidc = this;
|
|
794
|
+
const serviceWorker = await initWorkerAsync(oidc.configuration.service_worker_relative_url, oidc.configurationName);
|
|
795
|
+
if (!serviceWorker) {
|
|
796
|
+
const session = initSession(this.configurationName, oidc.configuration.redirect_uri, oidc.configuration.storage);
|
|
797
|
+
await session.setTokens(parsedTokens);
|
|
751
798
|
}
|
|
799
|
+
|
|
752
800
|
this.publishEvent(Oidc.eventNames.token_aquired, parsedTokens);
|
|
753
801
|
// @ts-ignore
|
|
754
802
|
return { parsedTokens, state:response.state, callbackPath : response.callbackPath};
|
|
@@ -774,9 +822,10 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
774
822
|
const sessionState = queryParams.session_state;
|
|
775
823
|
const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
|
|
776
824
|
let storage = null;
|
|
825
|
+
let nonceData = null;
|
|
777
826
|
if(serviceWorker){
|
|
778
827
|
serviceWorker.startKeepAliveServiceWorker();
|
|
779
|
-
|
|
828
|
+
//const serviceWorker = serviceWorker;
|
|
780
829
|
await serviceWorker.initAsync(oidcServerConfiguration, "loginCallbackAsync");
|
|
781
830
|
const items = await serviceWorker.loadItemsAsync();
|
|
782
831
|
storage = new MemoryStorageBackend(serviceWorker.saveItemsAsync, items);
|
|
@@ -786,14 +835,16 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
786
835
|
}
|
|
787
836
|
await storage.removeItem("dummy");
|
|
788
837
|
await serviceWorker.setSessionStateAsync(sessionState);
|
|
838
|
+
nonceData = await serviceWorker.getNonceAsync();
|
|
789
839
|
}else{
|
|
790
|
-
|
|
791
|
-
this.session = initSession(this.configurationName, redirectUri, configuration.storage ?? sessionStorage);
|
|
840
|
+
//this.session = initSession(this.configurationName, redirectUri, configuration.storage ?? sessionStorage);
|
|
792
841
|
const session = initSession(this.configurationName, redirectUri);
|
|
793
842
|
session.setSessionState(sessionState);
|
|
794
843
|
const items = await session.loadItemsAsync();
|
|
795
844
|
storage = new MemoryStorageBackend(session.saveItemsAsync, items);
|
|
845
|
+
nonceData = await session.getNonceAsync();
|
|
796
846
|
}
|
|
847
|
+
|
|
797
848
|
return new Promise((resolve, reject) => {
|
|
798
849
|
// @ts-ignore
|
|
799
850
|
let queryStringUtil = new NoHashQueryStringUtils();
|
|
@@ -853,6 +904,16 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
853
904
|
if (serviceWorker) {
|
|
854
905
|
const {tokens} = await serviceWorker.initAsync(oidcServerConfiguration, "syncTokensAsync");
|
|
855
906
|
tokenResponse = tokens;
|
|
907
|
+
};
|
|
908
|
+
if(!isTokensOidcValid(tokenResponse, nonceData.nonce, oidcServerConfiguration)){
|
|
909
|
+
const exception = new Error("Tokens are not OpenID valid");
|
|
910
|
+
if(timeoutId) {
|
|
911
|
+
clearTimeout(timeoutId);
|
|
912
|
+
this.timeoutId=null;
|
|
913
|
+
this.publishEvent(eventNames.loginCallbackAsync_error, exception);
|
|
914
|
+
console.error(exception);
|
|
915
|
+
reject(exception);
|
|
916
|
+
}
|
|
856
917
|
}
|
|
857
918
|
|
|
858
919
|
// @ts-ignore
|
|
@@ -971,6 +1032,10 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
971
1032
|
const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
|
|
972
1033
|
const tokenResponse = await performTokenRequestAsync(oidcServerConfiguration.tokenEndpoint, details, extras)
|
|
973
1034
|
if (tokenResponse.success) {
|
|
1035
|
+
if(!isTokensOidcValid(tokenResponse.data, null, oidcServerConfiguration)){
|
|
1036
|
+
this.publishEvent(eventNames.refreshTokensAsync_error, {message: `refresh token return not valid tokens` });
|
|
1037
|
+
return {tokens:null, status:"SESSION_LOST"};
|
|
1038
|
+
}
|
|
974
1039
|
this.publishEvent(eventNames.refreshTokensAsync_end, {success: tokenResponse.success});
|
|
975
1040
|
this.publishEvent(Oidc.eventNames.token_renewed, {});
|
|
976
1041
|
return {tokens: tokenResponse.data, status:"LOGGED_IN"};
|
|
@@ -1077,11 +1142,13 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
1077
1142
|
if(this.checkSessionIFrame){
|
|
1078
1143
|
this.checkSessionIFrame.stop();
|
|
1079
1144
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
await
|
|
1145
|
+
const oidc = this;
|
|
1146
|
+
const serviceWorker = await initWorkerAsync(oidc.configuration.service_worker_relative_url, oidc.configurationName);
|
|
1147
|
+
if (!serviceWorker) {
|
|
1148
|
+
const session = initSession(this.configurationName, oidc.configuration.redirect_uri, oidc.configuration.storage);
|
|
1149
|
+
await session.clearAsync(status);
|
|
1150
|
+
} else{
|
|
1151
|
+
await serviceWorker.clearAsync(status);
|
|
1085
1152
|
}
|
|
1086
1153
|
this.tokens = null;
|
|
1087
1154
|
this.userInfo = null;
|
|
@@ -51,7 +51,7 @@ export const setTokens = (tokens) =>{
|
|
|
51
51
|
else {
|
|
52
52
|
accessTokenPayload = extractAccessTokenPayload(tokens);
|
|
53
53
|
}
|
|
54
|
-
const _idTokenPayload = idTokenPayload(tokens.idToken);
|
|
54
|
+
const _idTokenPayload = tokens.idTokenPayload ? tokens.idTokenPayload : idTokenPayload(tokens.idToken);
|
|
55
55
|
|
|
56
56
|
const idTokenExipreAt =(_idTokenPayload && _idTokenPayload.exp) ? _idTokenPayload.exp: Number.MAX_VALUE;
|
|
57
57
|
const accessTokenExpiresAt = (accessTokenPayload && accessTokenPayload.exp)? accessTokenPayload.exp : tokens.issuedAt + tokens.expiresIn;
|
|
@@ -61,6 +61,7 @@ export const setTokens = (tokens) =>{
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
|
|
64
65
|
export const parseOriginalTokens= (tokens) =>{
|
|
65
66
|
if(!tokens){
|
|
66
67
|
return null;
|
|
@@ -104,4 +105,35 @@ export const isTokensValid= (tokens) =>{
|
|
|
104
105
|
return false;
|
|
105
106
|
}
|
|
106
107
|
return computeTimeLeft(0, tokens.expiresAt) > 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation (excluding rules #1, #4, #5, #7, #8, #12, and #13 which did not apply).
|
|
111
|
+
// https://github.com/openid/AppAuth-JS/issues/65
|
|
112
|
+
export const isTokensOidcValid =(tokens, nonce, oidcServerConfiguration) =>{
|
|
113
|
+
if(tokens.idTokenPayload) {
|
|
114
|
+
const idTokenPayload = tokens.idTokenPayload;
|
|
115
|
+
// 2: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery) MUST exactly match the value of the iss (issuer) Claim.
|
|
116
|
+
if(oidcServerConfiguration.issuer !== idTokenPayload.iss){
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
// 3: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience. The aud (audience) Claim MAY contain an array with more than one element. The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences not trusted by the Client.
|
|
120
|
+
|
|
121
|
+
// 6: If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer.
|
|
122
|
+
|
|
123
|
+
// 9: The current time MUST be before the time represented by the exp Claim.
|
|
124
|
+
const currentTimeUnixSecond = new Date().getTime() /1000;
|
|
125
|
+
if(idTokenPayload.exp && idTokenPayload.exp < currentTimeUnixSecond) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
// 10: The iat Claim can be used to reject tokens that were issued too far away from the current time, limiting the amount of time that nonces need to be stored to prevent attacks. The acceptable range is Client specific.
|
|
129
|
+
const timeInSevenDays = 60 * 60 * 24 * 7;
|
|
130
|
+
if(idTokenPayload.iat && (idTokenPayload.iat + timeInSevenDays) < currentTimeUnixSecond) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
// 11: If a nonce value was sent in the Authentication Request, a nonce Claim MUST be present and its value checked to verify that it is the same value as the one that was sent in the Authentication Request. The Client SHOULD check the nonce value for replay attacks. The precise method for detecting replay attacks is Client specific.
|
|
134
|
+
if (idTokenPayload.nonce && idTokenPayload.nonce !== nonce) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
107
139
|
}
|