@axa-fr/react-oidc 6.4.0 → 6.5.0-beta1

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.
@@ -21,7 +21,7 @@ import {getParseQueryStringFromLocation} from "./route-utils";
21
21
  import {AuthorizationServiceConfigurationJson} from "@openid/appauth/src/authorization_service_configuration";
22
22
  import {computeTimeLeft, isTokensOidcValid, isTokensValid, parseOriginalTokens, setTokens} from "./parseTokens";
23
23
 
24
- const performTokenRequestAsync= async (url, details, extras) => {
24
+ const performTokenRequestAsync= async (url, details, extras, oldTokens) => {
25
25
 
26
26
  for (let [key, value] of Object.entries(extras)) {
27
27
  if (details[key] === undefined) {
@@ -51,7 +51,7 @@ const performTokenRequestAsync= async (url, details, extras) => {
51
51
  const tokens = await response.json();
52
52
  return {
53
53
  success : true,
54
- data: parseOriginalTokens(tokens)
54
+ data: parseOriginalTokens(tokens, oldTokens)
55
55
  };
56
56
  }
57
57
 
@@ -154,29 +154,32 @@ const loginCallbackWithAutoTokensRenewAsync = async (oidc) => {
154
154
  return { state, callbackPath };
155
155
  }
156
156
 
157
- async function renewTokensAndStartTimerAsync(oidc, refreshToken, forceRefresh =false) {
158
- const {tokens, status} = await oidc.synchroniseTokensAsync(refreshToken, 0, forceRefresh);
157
+ async function renewTokensAndStartTimerAsync(oidc, refreshToken, forceRefresh =false, extras:StringMap=null) {
158
+ const {tokens, status} = await oidc.synchroniseTokensAsync(refreshToken, 0, forceRefresh, extras);
159
159
  oidc.tokens = tokens;
160
- if (!oidc.serviceWorker) {
161
- 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);
162
164
  }
165
+
163
166
  if (!oidc.tokens) {
164
167
  await oidc.destroyAsync(status);
165
168
  return;
166
169
  }
167
170
 
168
171
  if (oidc.timeoutId) {
169
- oidc.timeoutId = autoRenewTokens(oidc, tokens.refreshToken, oidc.tokens.expiresAt);
172
+ oidc.timeoutId = autoRenewTokens(oidc, tokens.refreshToken, oidc.tokens.expiresAt, extras);
170
173
  }
171
174
  }
172
175
 
173
- const autoRenewTokens = (oidc, refreshToken, expiresAt) => {
176
+ const autoRenewTokens = (oidc, refreshToken, expiresAt, extras:StringMap=null) => {
174
177
  const refreshTimeBeforeTokensExpirationInSecond = oidc.configuration.refresh_time_before_tokens_expiration_in_second;
175
178
  return timer.setTimeout(async () => {
176
179
  const timeLeft = computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond, expiresAt);
177
180
  const timeInfo = { timeLeft };
178
181
  oidc.publishEvent(Oidc.eventNames.token_timer, timeInfo);
179
- await renewTokensAndStartTimerAsync(oidc, refreshToken);
182
+ await renewTokensAndStartTimerAsync(oidc, refreshToken, false, extras);
180
183
  }, 1000);
181
184
  }
182
185
 
@@ -325,9 +328,9 @@ export class Oidc {
325
328
  public tokens: null;
326
329
  public events: Array<any>;
327
330
  private timeoutId: NodeJS.Timeout;
328
- private serviceWorker?: any;
331
+ //private serviceWorker?: any;
329
332
  private configurationName: string;
330
- private session?: any;
333
+ //private session?: any;
331
334
  private checkSessionIFrame: CheckSessionIFrame;
332
335
  constructor(configuration:OidcConfiguration, configurationName="default") {
333
336
  let silent_login_uri = configuration.silent_login_uri;
@@ -346,8 +349,8 @@ export class Oidc {
346
349
  this.userInfo = null;
347
350
  this.events = [];
348
351
  this.timeoutId = null;
349
- this.serviceWorker = null;
350
- this.session = null;
352
+ //this.serviceWorker = null;
353
+ //this.session = null;
351
354
  this.synchroniseTokensAsync.bind(this);
352
355
  this.loginCallbackWithAutoTokensRenewAsync.bind(this);
353
356
  this.initAsync.bind(this);
@@ -560,7 +563,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
560
563
  serviceWorker.startKeepAliveServiceWorker();
561
564
  // @ts-ignore
562
565
  this.tokens = tokens;
563
- this.serviceWorker = serviceWorker;
566
+ //this.serviceWorker = serviceWorker;
564
567
  // @ts-ignore
565
568
  this.timeoutId = autoRenewTokens(this, this.tokens.refreshToken, this.tokens.expiresAt);
566
569
  const sessionState = await serviceWorker.getSessionStateAsync();
@@ -588,7 +591,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
588
591
  // @ts-ignore
589
592
  this.tokens = setTokens(tokens);
590
593
  //session.setTokens(this.tokens);
591
- this.session = session;
594
+ //this.session = session;
592
595
  // @ts-ignore
593
596
  this.timeoutId = autoRenewTokens(this, tokens.refreshToken, this.tokens.expiresAt);
594
597
  const sessionState = session.getSessionState();
@@ -624,18 +627,45 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
624
627
  }
625
628
 
626
629
  loginPromise: Promise<any>=null;
627
- 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, isSilentSignin:boolean=false, scope:string=undefined, silentLoginOnly = false) {
628
631
  if(this.loginPromise !== null){
629
632
  return this.loginPromise;
630
633
  }
631
634
 
632
635
  const loginLocalAsync=async () => {
633
- try {
636
+
634
637
  const location = window.location;
635
638
  const url = callbackPath || location.pathname + (location.search || '') + (location.hash || '');
636
- this.publishEvent(eventNames.loginAsync_begin, {});
639
+
637
640
  const configuration = this.configuration;
641
+ let state = undefined;
642
+ if(extras && "state" in extras){
643
+ state = extras["state"];
644
+ delete extras["state"];
645
+ }
646
+
638
647
 
648
+ if(silentLoginOnly){
649
+ try {
650
+ const extraFinal = extras ?? configuration.extras ?? {};
651
+ const silentResult = await this.silentLoginAsync({
652
+ ...extraFinal,
653
+ prompt: "none"
654
+ }, state, scope);
655
+
656
+ if (silentResult) {
657
+ this.tokens = silentResult.tokens;
658
+ this.publishEvent(eventNames.token_aquired, {});
659
+ // @ts-ignore
660
+ this.timeoutId = autoRenewTokens(this, this.tokens.refreshToken, this.tokens.expiresAt, extras);
661
+ return {};
662
+ }
663
+ }catch (e) {
664
+ return e;
665
+ }
666
+ }
667
+ this.publishEvent(eventNames.loginAsync_begin, {});
668
+ try {
639
669
  const redirectUri = isSilentSignin ? configuration.silent_redirect_uri : configuration.redirect_uri;
640
670
  if (!scope) {
641
671
  scope = configuration.scope;
@@ -766,9 +796,13 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
766
796
  const tokens = response.tokens;
767
797
  const parsedTokens = setTokens(tokens);
768
798
  this.tokens = parsedTokens;
769
- if(!this.serviceWorker){
770
- await this.session.setTokens(parsedTokens);
799
+ const oidc = this;
800
+ const serviceWorker = await initWorkerAsync(oidc.configuration.service_worker_relative_url, oidc.configurationName);
801
+ if (!serviceWorker) {
802
+ const session = initSession(this.configurationName, oidc.configuration.redirect_uri, oidc.configuration.storage);
803
+ await session.setTokens(parsedTokens);
771
804
  }
805
+
772
806
  this.publishEvent(Oidc.eventNames.token_aquired, parsedTokens);
773
807
  // @ts-ignore
774
808
  return { parsedTokens, state:response.state, callbackPath : response.callbackPath};
@@ -797,7 +831,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
797
831
  let nonceData = null;
798
832
  if(serviceWorker){
799
833
  serviceWorker.startKeepAliveServiceWorker();
800
- this.serviceWorker = serviceWorker;
834
+ //const serviceWorker = serviceWorker;
801
835
  await serviceWorker.initAsync(oidcServerConfiguration, "loginCallbackAsync");
802
836
  const items = await serviceWorker.loadItemsAsync();
803
837
  storage = new MemoryStorageBackend(serviceWorker.saveItemsAsync, items);
@@ -809,7 +843,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
809
843
  await serviceWorker.setSessionStateAsync(sessionState);
810
844
  nonceData = await serviceWorker.getNonceAsync();
811
845
  }else{
812
- this.session = initSession(this.configurationName, redirectUri, configuration.storage ?? sessionStorage);
846
+ //this.session = initSession(this.configurationName, redirectUri, configuration.storage ?? sessionStorage);
813
847
  const session = initSession(this.configurationName, redirectUri);
814
848
  session.setSessionState(sessionState);
815
849
  const items = await session.loadItemsAsync();
@@ -918,7 +952,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
918
952
  }
919
953
  }
920
954
 
921
- async synchroniseTokensAsync(refreshToken, index=0, forceRefresh =false) {
955
+ async synchroniseTokensAsync(refreshToken, index=0, forceRefresh =false, extras:StringMap=null) {
922
956
 
923
957
  if (document.hidden) {
924
958
  await sleepAsync(1000);
@@ -931,13 +965,17 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
931
965
  numberTryOnline--;
932
966
  this.publishEvent(eventNames.refreshTokensAsync, {message: `wait because navigator is offline try ${numberTryOnline}` });
933
967
  }
934
-
968
+ if(!extras){
969
+ extras = {}
970
+ }
935
971
  const configuration = this.configuration;
936
972
  const localsilentLoginAsync= async () => {
937
973
  try {
938
974
  const loginParams = getLoginParams(this.configurationName, configuration.redirect_uri);
975
+
939
976
  const silent_token_response = await this.silentLoginAsync({
940
977
  ...loginParams.extras,
978
+ ...extras,
941
979
  prompt: "none"
942
980
  }, loginParams.state);
943
981
  if (silent_token_response) {
@@ -960,7 +998,6 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
960
998
 
961
999
  if (index <=4) {
962
1000
  try {
963
-
964
1001
  const { status, tokens } = await this.syncTokensInfoAsync(configuration, this.configurationName, this.tokens, forceRefresh);
965
1002
  switch (status) {
966
1003
  case "SESSION_LOST":
@@ -989,12 +1026,9 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
989
1026
  const clientId = configuration.client_id;
990
1027
  const redirectUri = configuration.redirect_uri;
991
1028
  const authority = configuration.authority;
992
- let extras = {};
993
- if(configuration.token_request_extras) {
994
- for (let [key, value] of Object.entries(configuration.token_request_extras)) {
995
- extras[key] = value;
996
- }
997
- }
1029
+ const tokenExtras = configuration.token_request_extras ? configuration.token_request_extras : {};
1030
+ let finalExtras = {...tokenExtras, ...extras};
1031
+
998
1032
  const details = {
999
1033
  client_id: clientId,
1000
1034
  redirect_uri: redirectUri,
@@ -1002,7 +1036,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
1002
1036
  refresh_token: tokens.refreshToken,
1003
1037
  };
1004
1038
  const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
1005
- const tokenResponse = await performTokenRequestAsync(oidcServerConfiguration.tokenEndpoint, details, extras)
1039
+ const tokenResponse = await performTokenRequestAsync(oidcServerConfiguration.tokenEndpoint, details, finalExtras, tokens);
1006
1040
  if (tokenResponse.success) {
1007
1041
  if(!isTokensOidcValid(tokenResponse.data, null, oidcServerConfiguration)){
1008
1042
  this.publishEvent(eventNames.refreshTokensAsync_error, {message: `refresh token return not valid tokens` });
@@ -1099,13 +1133,13 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
1099
1133
  })
1100
1134
  }
1101
1135
 
1102
- async renewTokensAsync (){
1136
+ async renewTokensAsync (extras:StringMap=null){
1103
1137
  if(!this.timeoutId){
1104
1138
  return;
1105
1139
  }
1106
1140
  timer.clearTimeout(this.timeoutId);
1107
1141
  // @ts-ignore
1108
- await renewTokensAndStartTimerAsync(this, this.tokens.refreshToken, true);
1142
+ await renewTokensAndStartTimerAsync(this, this.tokens.refreshToken, true, extras);
1109
1143
  }
1110
1144
 
1111
1145
  async destroyAsync(status) {
@@ -1114,11 +1148,13 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
1114
1148
  if(this.checkSessionIFrame){
1115
1149
  this.checkSessionIFrame.stop();
1116
1150
  }
1117
- if(this.serviceWorker){
1118
- await this.serviceWorker.clearAsync(status);
1119
- }
1120
- if(this.session){
1121
- await this.session.clearAsync(status);
1151
+ const oidc = this;
1152
+ const serviceWorker = await initWorkerAsync(oidc.configuration.service_worker_relative_url, oidc.configurationName);
1153
+ if (!serviceWorker) {
1154
+ const session = initSession(this.configurationName, oidc.configuration.redirect_uri, oidc.configuration.storage);
1155
+ await session.clearAsync(status);
1156
+ } else{
1157
+ await serviceWorker.clearAsync(status);
1122
1158
  }
1123
1159
  this.tokens = null;
1124
1160
  this.userInfo = null;
@@ -33,7 +33,7 @@ const extractAccessTokenPayload = tokens => {
33
33
  };
34
34
 
35
35
 
36
- export const setTokens = (tokens) =>{
36
+ export const setTokens = (tokens, oldTokens=null) =>{
37
37
 
38
38
  if(!tokens){
39
39
  return null;
@@ -57,12 +57,19 @@ export const setTokens = (tokens) =>{
57
57
  const accessTokenExpiresAt = (accessTokenPayload && accessTokenPayload.exp)? accessTokenPayload.exp : tokens.issuedAt + tokens.expiresIn;
58
58
  const expiresAt = idTokenExipreAt < accessTokenExpiresAt ? idTokenExipreAt : accessTokenExpiresAt;
59
59
 
60
- return {...tokens, idTokenPayload: _idTokenPayload, accessTokenPayload, expiresAt};
60
+ const newTokens = {...tokens, idTokenPayload: _idTokenPayload, accessTokenPayload, expiresAt};
61
+ // When refresh_token is not rotated we reuse ald refresh_token
62
+ if(oldTokens != null && "refreshToken" in oldTokens && !("refreshToken" in tokens)){
63
+ const refreshToken = oldTokens.refreshToken
64
+ return {...newTokens, refreshToken};
65
+ }
66
+
67
+ return newTokens;
61
68
  }
62
69
 
63
70
 
64
71
 
65
- export const parseOriginalTokens= (tokens) =>{
72
+ export const parseOriginalTokens= (tokens, oldTokens) =>{
66
73
  if(!tokens){
67
74
  return null;
68
75
  }
@@ -75,12 +82,16 @@ export const parseOriginalTokens= (tokens) =>{
75
82
  accessToken: tokens.access_token,
76
83
  expiresIn: tokens.expires_in,
77
84
  idToken: tokens.id_token,
78
- refreshToken: tokens.refresh_token,
79
85
  scope: tokens.scope,
80
86
  tokenType: tokens.token_type,
81
87
  issuedAt: tokens.issued_at
82
88
  };
83
89
 
90
+ if("refresh_token" in tokens) {
91
+ // @ts-ignore
92
+ data.refreshToken= tokens.refresh_token;
93
+ }
94
+
84
95
 
85
96
  if(tokens.accessTokenPayload !== undefined){
86
97
  // @ts-ignore
@@ -92,7 +103,7 @@ export const parseOriginalTokens= (tokens) =>{
92
103
  data.idTokenPayload = tokens.idTokenPayload;
93
104
  }
94
105
 
95
- return setTokens(data);
106
+ return setTokens(data, oldTokens);
96
107
  }
97
108
 
98
109
  export const computeTimeLeft = (refreshTimeBeforeTokensExpirationInSecond, expiresAt)=>{