@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.
@@ -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;AAGD,eAAO,MAAM,mBAAmB,sBA+B/B,CAAA;AAED,eAAO,MAAM,eAAe,4EAG3B,CAAA;AAED,eAAO,MAAM,aAAa,0BAKzB,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":"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"}
1
+ {"version":3,"file":"parseTokens.js","sourceRoot":"","sources":["../../src/oidc/vanilla/parseTokens.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axa-fr/react-oidc",
3
- "version": "6.3.1",
3
+ "version": "6.5.0-beta0",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "jsnext:main": "dist/index.js",
@@ -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
- const key = REFRESH_TOKEN + '_'+ currentDb.configurationName;
219
- if(currentDb && currentDb.tokens != null && actualBody.includes(key)) {
220
- newBody = newBody.replace(key, encodeURIComponent(currentDb.tokens.refresh_token));
221
- currentDatabase = currentDb;
222
- break;
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 { saveItemsAsync, loadItemsAsync, clearAsync, initAsync, setTokens, getTokens, setSessionState, getSessionState };
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
  }
@@ -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
- if (!oidc.serviceWorker) {
157
- await oidc.session.setTokens(oidc.tokens);
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
- try {
636
+
629
637
  const location = window.location;
630
638
  const url = callbackPath || location.pathname + (location.search || '') + (location.hash || '');
631
- this.publishEvent(eventNames.loginAsync_begin, {});
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
- const extraFinal = extras ?? configuration.extras ?? {};
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
- if(!this.serviceWorker){
750
- await this.session.setTokens(parsedTokens);
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
- this.serviceWorker = serviceWorker;
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
- if(this.serviceWorker){
1081
- await this.serviceWorker.clearAsync(status);
1082
- }
1083
- if(this.session){
1084
- await this.session.clearAsync(status);
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
  }