@axa-fr/react-oidc 5.7.0-aplha0

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.
Files changed (160) hide show
  1. package/README.md +502 -0
  2. package/dist/FetchToken.d.ts +10 -0
  3. package/dist/FetchToken.d.ts.map +1 -0
  4. package/dist/FetchToken.js +107 -0
  5. package/dist/FetchToken.js.map +1 -0
  6. package/dist/OidcProvider.d.ts +25 -0
  7. package/dist/OidcProvider.d.ts.map +1 -0
  8. package/dist/OidcProvider.js +133 -0
  9. package/dist/OidcProvider.js.map +1 -0
  10. package/dist/OidcSecure.d.ts +10 -0
  11. package/dist/OidcSecure.d.ts.map +1 -0
  12. package/dist/OidcSecure.js +68 -0
  13. package/dist/OidcSecure.js.map +1 -0
  14. package/dist/OidcServiceWorker.js +272 -0
  15. package/dist/OidcTrustedDomains.js +6 -0
  16. package/dist/ReactOidc.d.ts +17 -0
  17. package/dist/ReactOidc.d.ts.map +1 -0
  18. package/dist/ReactOidc.js +106 -0
  19. package/dist/ReactOidc.js.map +1 -0
  20. package/dist/User.d.ts +15 -0
  21. package/dist/User.d.ts.map +1 -0
  22. package/dist/User.js +48 -0
  23. package/dist/User.js.map +1 -0
  24. package/dist/core/default-component/AuthenticateError.component.d.ts +4 -0
  25. package/dist/core/default-component/AuthenticateError.component.d.ts.map +1 -0
  26. package/dist/core/default-component/AuthenticateError.component.js +32 -0
  27. package/dist/core/default-component/AuthenticateError.component.js.map +1 -0
  28. package/dist/core/default-component/Authenticating.component.d.ts +4 -0
  29. package/dist/core/default-component/Authenticating.component.d.ts.map +1 -0
  30. package/dist/core/default-component/Authenticating.component.js +32 -0
  31. package/dist/core/default-component/Authenticating.component.js.map +1 -0
  32. package/dist/core/default-component/Callback.component.d.ts +5 -0
  33. package/dist/core/default-component/Callback.component.d.ts.map +1 -0
  34. package/dist/core/default-component/Callback.component.js +118 -0
  35. package/dist/core/default-component/Callback.component.js.map +1 -0
  36. package/dist/core/default-component/Loading.component.d.ts +4 -0
  37. package/dist/core/default-component/Loading.component.d.ts.map +1 -0
  38. package/dist/core/default-component/Loading.component.js +29 -0
  39. package/dist/core/default-component/Loading.component.js.map +1 -0
  40. package/dist/core/default-component/ServiceWorkerInstall.component.d.ts +4 -0
  41. package/dist/core/default-component/ServiceWorkerInstall.component.d.ts.map +1 -0
  42. package/dist/core/default-component/ServiceWorkerInstall.component.js +122 -0
  43. package/dist/core/default-component/ServiceWorkerInstall.component.js.map +1 -0
  44. package/dist/core/default-component/ServiceWorkerNotSupported.component.d.ts +4 -0
  45. package/dist/core/default-component/ServiceWorkerNotSupported.component.d.ts.map +1 -0
  46. package/dist/core/default-component/ServiceWorkerNotSupported.component.js +32 -0
  47. package/dist/core/default-component/ServiceWorkerNotSupported.component.js.map +1 -0
  48. package/dist/core/default-component/SessionLost.component.d.ts +4 -0
  49. package/dist/core/default-component/SessionLost.component.d.ts.map +1 -0
  50. package/dist/core/default-component/SessionLost.component.js +14 -0
  51. package/dist/core/default-component/SessionLost.component.js.map +1 -0
  52. package/dist/core/default-component/SilentCallback.component.d.ts +4 -0
  53. package/dist/core/default-component/SilentCallback.component.d.ts.map +1 -0
  54. package/dist/core/default-component/SilentCallback.component.js +96 -0
  55. package/dist/core/default-component/SilentCallback.component.js.map +1 -0
  56. package/dist/core/default-component/index.d.ts +7 -0
  57. package/dist/core/default-component/index.d.ts.map +1 -0
  58. package/dist/core/default-component/index.js +20 -0
  59. package/dist/core/default-component/index.js.map +1 -0
  60. package/dist/core/routes/OidcRoutes.d.ts +12 -0
  61. package/dist/core/routes/OidcRoutes.d.ts.map +1 -0
  62. package/dist/core/routes/OidcRoutes.js +71 -0
  63. package/dist/core/routes/OidcRoutes.js.map +1 -0
  64. package/dist/core/routes/index.d.ts +3 -0
  65. package/dist/core/routes/index.d.ts.map +1 -0
  66. package/dist/core/routes/index.js +9 -0
  67. package/dist/core/routes/index.js.map +1 -0
  68. package/dist/core/routes/route-utils.d.ts +2 -0
  69. package/dist/core/routes/route-utils.d.ts.map +1 -0
  70. package/dist/core/routes/route-utils.js +32 -0
  71. package/dist/core/routes/route-utils.js.map +1 -0
  72. package/dist/core/routes/withRouter.d.ts +19 -0
  73. package/dist/core/routes/withRouter.d.ts.map +1 -0
  74. package/dist/core/routes/withRouter.js +33 -0
  75. package/dist/core/routes/withRouter.js.map +1 -0
  76. package/dist/index.d.ts +6 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +19 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/vanilla/index.d.ts +2 -0
  81. package/dist/vanilla/index.d.ts.map +1 -0
  82. package/dist/vanilla/index.js +6 -0
  83. package/dist/vanilla/index.js.map +1 -0
  84. package/dist/vanilla/initSession.d.ts +11 -0
  85. package/dist/vanilla/initSession.d.ts.map +1 -0
  86. package/dist/vanilla/initSession.js +72 -0
  87. package/dist/vanilla/initSession.js.map +1 -0
  88. package/dist/vanilla/initWorker.d.ts +13 -0
  89. package/dist/vanilla/initWorker.d.ts.map +1 -0
  90. package/dist/vanilla/initWorker.js +211 -0
  91. package/dist/vanilla/initWorker.js.map +1 -0
  92. package/dist/vanilla/memoryStorageBackend.d.ts +10 -0
  93. package/dist/vanilla/memoryStorageBackend.d.ts.map +1 -0
  94. package/dist/vanilla/memoryStorageBackend.js +33 -0
  95. package/dist/vanilla/memoryStorageBackend.js.map +1 -0
  96. package/dist/vanilla/noHashQueryStringUtils.d.ts +5 -0
  97. package/dist/vanilla/noHashQueryStringUtils.d.ts.map +1 -0
  98. package/dist/vanilla/noHashQueryStringUtils.js +31 -0
  99. package/dist/vanilla/noHashQueryStringUtils.js.map +1 -0
  100. package/dist/vanilla/oidc.d.ts +77 -0
  101. package/dist/vanilla/oidc.d.ts.map +1 -0
  102. package/dist/vanilla/oidc.js +814 -0
  103. package/dist/vanilla/oidc.js.map +1 -0
  104. package/dist/vanilla/timer.d.ts +8 -0
  105. package/dist/vanilla/timer.d.ts.map +1 -0
  106. package/dist/vanilla/timer.js +135 -0
  107. package/dist/vanilla/timer.js.map +1 -0
  108. package/package.json +73 -0
  109. package/src/App.css +38 -0
  110. package/src/App.specold.tsx +46 -0
  111. package/src/App.tsx +61 -0
  112. package/src/FetchUser.tsx +53 -0
  113. package/src/Home.tsx +20 -0
  114. package/src/MultiAuth.tsx +114 -0
  115. package/src/Profile.tsx +77 -0
  116. package/src/configurations.ts +53 -0
  117. package/src/index.css +13 -0
  118. package/src/index.tsx +9 -0
  119. package/src/logo.svg +7 -0
  120. package/src/oidc/FetchToken.tsx +51 -0
  121. package/src/oidc/OidcProvider.tsx +165 -0
  122. package/src/oidc/OidcSecure.tsx +32 -0
  123. package/src/oidc/ReactOidc.tsx +112 -0
  124. package/src/oidc/User.ts +38 -0
  125. package/src/oidc/core/default-component/AuthenticateError.component.tsx +13 -0
  126. package/src/oidc/core/default-component/Authenticating.component.tsx +13 -0
  127. package/src/oidc/core/default-component/Callback.component.tsx +49 -0
  128. package/src/oidc/core/default-component/Loading.component.tsx +10 -0
  129. package/src/oidc/core/default-component/ServiceWorkerInstall.component.tsx +51 -0
  130. package/src/oidc/core/default-component/ServiceWorkerNotSupported.component.tsx +13 -0
  131. package/src/oidc/core/default-component/SessionLost.component.tsx +14 -0
  132. package/src/oidc/core/default-component/SilentCallback.component.tsx +31 -0
  133. package/src/oidc/core/default-component/index.ts +6 -0
  134. package/src/oidc/core/routes/OidcRoutes.spec.tsx +16 -0
  135. package/src/oidc/core/routes/OidcRoutes.tsx +69 -0
  136. package/src/oidc/core/routes/__snapshots__/OidcRoutes.spec.tsx.snap +7 -0
  137. package/src/oidc/core/routes/index.ts +2 -0
  138. package/src/oidc/core/routes/route-utils.spec.ts +9 -0
  139. package/src/oidc/core/routes/route-utils.ts +34 -0
  140. package/src/oidc/core/routes/withRouter.spec.tsx +48 -0
  141. package/src/oidc/core/routes/withRouter.tsx +60 -0
  142. package/src/oidc/index.ts +5 -0
  143. package/src/oidc/vanilla/OidcServiceWorker.js +272 -0
  144. package/src/oidc/vanilla/OidcTrustedDomains.js +6 -0
  145. package/src/oidc/vanilla/index.ts +1 -0
  146. package/src/oidc/vanilla/initSession.ts +36 -0
  147. package/src/oidc/vanilla/initWorker.ts +153 -0
  148. package/src/oidc/vanilla/memoryStorageBackend.ts +33 -0
  149. package/src/oidc/vanilla/noHashQueryStringUtils.ts +7 -0
  150. package/src/oidc/vanilla/oidc.ts +600 -0
  151. package/src/oidc/vanilla/timer.ts +157 -0
  152. package/src/override/AuthenticateError.component.tsx +14 -0
  153. package/src/override/Authenticating.component.tsx +14 -0
  154. package/src/override/Callback.component.tsx +13 -0
  155. package/src/override/Loading.component.tsx +13 -0
  156. package/src/override/ServiceWorkerNotSupported.component.tsx +15 -0
  157. package/src/override/SessionLost.component.tsx +21 -0
  158. package/src/override/style.ts +10 -0
  159. package/src/setupTests.js +5 -0
  160. package/tsconfig.json +38 -0
@@ -0,0 +1,600 @@
1
+ import {
2
+ AuthorizationNotifier,
3
+ AuthorizationRequest,
4
+ AuthorizationServiceConfiguration,
5
+ BaseTokenRequestHandler,
6
+ DefaultCrypto,
7
+ FetchRequestor,
8
+ GRANT_TYPE_AUTHORIZATION_CODE,
9
+ GRANT_TYPE_REFRESH_TOKEN,
10
+ RedirectRequestHandler,
11
+ TokenRequest
12
+ } from '@openid/appauth';
13
+ import {NoHashQueryStringUtils} from './noHashQueryStringUtils';
14
+ import {initWorkerAsync} from './initWorker'
15
+ import {MemoryStorageBackend} from "./memoryStorageBackend";
16
+ import {initSession} from "./initSession";
17
+ import timer from './timer';
18
+
19
+ const isInIframe = () => {
20
+ try {
21
+ return window.self !== window.top;
22
+ } catch (e) {
23
+ return true;
24
+ }
25
+ }
26
+
27
+ const idTokenPayload = (token) => {
28
+ const base64Url = token.split('.')[1];
29
+ const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
30
+ const jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
31
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
32
+ }).join(''));
33
+
34
+ return JSON.parse(jsonPayload);
35
+ }
36
+
37
+ const countLetter = (str, find)=> {
38
+ return (str.split(find)).length - 1;
39
+ }
40
+
41
+ const extractAccessTokenPayload = tokens => {
42
+ if(tokens.accessTokenPayload)
43
+ {
44
+ return tokens.accessTokenPayload;
45
+ }
46
+ const accessToken = tokens.accessToken;
47
+ try{
48
+ if (!accessToken || countLetter(accessToken,'.') === 2) {
49
+ return null;
50
+ }
51
+ return JSON.parse(atob(accessToken.split('.')[1]));
52
+ } catch (e) {
53
+ console.warn(e);
54
+ }
55
+ return null;
56
+ };
57
+
58
+ export interface StringMap {
59
+ [key: string]: string;
60
+ }
61
+
62
+ export interface AuthorityConfiguration {
63
+ authorization_endpoint: string;
64
+ token_endpoint: string;
65
+ revocation_endpoint: string;
66
+ end_session_endpoint?: string;
67
+ userinfo_endpoint?: string;
68
+ }
69
+
70
+ const refresh_token_scope = "offline_access";
71
+ export type OidcConfiguration = {
72
+ client_id: string,
73
+ redirect_uri: string,
74
+ silent_redirect_uri?:string,
75
+ silent_signin_timeout?:number,
76
+ scope: string,
77
+ authority: string,
78
+ authority_configuration?: AuthorityConfiguration,
79
+ refresh_time_before_tokens_expiration_in_second?: number,
80
+ service_worker_relative_url?:string,
81
+ service_worker_only?:boolean,
82
+ extras?:StringMap
83
+ token_request_extras?:StringMap,
84
+ };
85
+
86
+ const oidcDatabase = {};
87
+ const oidcFactory = (configuration: OidcConfiguration, name="default") => {
88
+ if(oidcDatabase[name]){
89
+ return oidcDatabase[name];
90
+ }
91
+ oidcDatabase[name] = new Oidc(configuration, name)
92
+ return oidcDatabase[name];
93
+ }
94
+
95
+ const loginCallbackWithAutoTokensRenewAsync = async (oidc) => {
96
+ const response = await oidc.loginCallbackAsync();
97
+ const tokens = response.tokens
98
+ oidc.tokens = await setTokensAsync(oidc.serviceWorker, tokens);
99
+ if(!oidc.serviceWorker){
100
+ await oidc.session.setTokens(oidc.tokens);
101
+ }
102
+ oidc.publishEvent(Oidc.eventNames.token_aquired, oidc.tokens);
103
+ oidc.timeoutId = await autoRenewTokensAsync(oidc, tokens.refreshToken, oidc.tokens.expiresAt)
104
+ return response.state;
105
+ }
106
+
107
+ const autoRenewTokensAsync = async (oidc, refreshToken, expiresAt) => {
108
+ const refreshTimeBeforeTokensExpirationInSecond = oidc.configuration.refresh_time_before_tokens_expiration_in_second ?? 60;
109
+ return timer.setTimeout(async () => {
110
+ const currentTimeUnixSecond = new Date().getTime() /1000;
111
+ const timeInfo = { timeLeft:((expiresAt - refreshTimeBeforeTokensExpirationInSecond)- currentTimeUnixSecond)};
112
+ oidc.publishEvent(Oidc.eventNames.token_timer, timeInfo);
113
+ if(currentTimeUnixSecond > (expiresAt - refreshTimeBeforeTokensExpirationInSecond)) {
114
+ const tokens = await oidc.refreshTokensAsync(refreshToken);
115
+ oidc.tokens= await setTokensAsync(oidc.serviceWorker, tokens);
116
+ if(!oidc.serviceWorker){
117
+ await oidc.session.setTokens(oidc.tokens);
118
+ }
119
+ if(!oidc.tokens){
120
+ return;
121
+ }
122
+ oidc.publishEvent(Oidc.eventNames.token_renewed, oidc.tokens);
123
+ oidc.timeoutId = await autoRenewTokensAsync(oidc, tokens.refreshToken, oidc.tokens.expiresAt);
124
+ } else{
125
+ oidc.timeoutId = await autoRenewTokensAsync(oidc, refreshToken, expiresAt)
126
+ }
127
+ }, 1000);
128
+ }
129
+
130
+ const userInfoAsync = async (oidc) => {
131
+ if(oidc.userInfo != null){
132
+ return oidc.userInfo;
133
+ }
134
+ if(!oidc.tokens){
135
+ return null;
136
+ }
137
+ const accessToken = oidc.tokens.accessToken;
138
+
139
+ const oidcServerConfiguration = await oidc.initAsync(oidc.configuration.authority, oidc.configuration.authority_configuration);
140
+ const url = oidcServerConfiguration.userInfoEndpoint;
141
+ const fetchUserInfo = async (accessToken) => {
142
+ const res = await fetch(url, {
143
+ headers: {
144
+ authorization: `Bearer ${accessToken}`
145
+ }
146
+ });
147
+
148
+ if(res.status != 200 ){
149
+ return null;
150
+ }
151
+
152
+ return res.json();
153
+ };
154
+ const userInfo = await fetchUserInfo(accessToken);
155
+ oidc.userInfo= userInfo;
156
+ return userInfo;
157
+ }
158
+
159
+ const setTokensAsync = async (serviceWorker, tokens) =>{
160
+ let accessTokenPayload;
161
+ if(tokens == null){
162
+ if(serviceWorker){
163
+ await serviceWorker.clearAsync();
164
+ }
165
+ return null;
166
+ }
167
+ if(serviceWorker){
168
+ accessTokenPayload = await serviceWorker.getAccessTokenPayloadAsync();
169
+ }
170
+ else {
171
+ accessTokenPayload = extractAccessTokenPayload(tokens);
172
+ }
173
+ const expiresAt = tokens.issuedAt + tokens.expiresIn;
174
+ return {...tokens, idTokenPayload: idTokenPayload(tokens.idToken), accessTokenPayload, expiresAt};
175
+ }
176
+
177
+ const eventNames = {
178
+ service_worker_not_supported_by_browser: "service_worker_not_supported_by_browser",
179
+ token_aquired: "token_aquired",
180
+ token_renewed: "token_renewed",
181
+ token_timer: "token_timer",
182
+ loginAsync_begin:"loginAsync_begin",
183
+ loginAsync_error:"loginAsync_error",
184
+ loginCallbackAsync_begin:"loginCallbackAsync_begin",
185
+ loginCallbackAsync_end:"loginCallbackAsync_end",
186
+ loginCallbackAsync_error:"loginCallbackAsync_error",
187
+ refreshTokensAsync_begin: "refreshTokensAsync_begin",
188
+ refreshTokensAsync_end: "refreshTokensAsync_end",
189
+ refreshTokensAsync_error: "refreshTokensAsync_error",
190
+ refreshTokensAsync_silent_begin: "refreshTokensAsync_silent_begin",
191
+ refreshTokensAsync_silent_end: "refreshTokensAsync_silent_end",
192
+ refreshTokensAsync_silent_error: "refreshTokensAsync_silent_error",
193
+ tryKeepExistingSessionAsync_begin: "tryKeepExistingSessionAsync_begin",
194
+ tryKeepExistingSessionAsync_end: "tryKeepExistingSessionAsync_end",
195
+ tryKeepExistingSessionAsync_error: "tryKeepExistingSessionAsync_error",
196
+ silentSigninAsync_begin: "silentSigninAsync_begin",
197
+ silentSigninAsync_end: "silentSigninAsync_end",
198
+ silentSigninAsync_error: "silentSigninAsync_error",
199
+ }
200
+
201
+ const getRandomInt = (max) => {
202
+ return Math.floor(Math.random() * max);
203
+ }
204
+
205
+ export class Oidc {
206
+ public configuration: OidcConfiguration;
207
+ public userInfo: null;
208
+ public tokens: null;
209
+ public events: Array<any>;
210
+ private timeoutId: NodeJS.Timeout;
211
+ private serviceWorker?: any;
212
+ private configurationName: string;
213
+ private session?: any;
214
+ constructor(configuration:OidcConfiguration, configurationName="default") {
215
+ this.configuration = configuration
216
+ this.configurationName= configurationName;
217
+ this.tokens = null
218
+ this.userInfo = null;
219
+ this.events = [];
220
+ this.timeoutId = null;
221
+ this.serviceWorker = null;
222
+ this.session = null;
223
+ this.refreshTokensAsync.bind(this);
224
+ this.loginCallbackWithAutoTokensRenewAsync.bind(this);
225
+ this.initAsync.bind(this);
226
+ this.loginCallbackAsync.bind(this);
227
+ this.subscriveEvents.bind(this);
228
+ this.removeEventSubscription.bind(this);
229
+ this.publishEvent.bind(this);
230
+ this.destroyAsync.bind(this);
231
+ }
232
+
233
+ subscriveEvents(func){
234
+ const id = getRandomInt(9999999999999).toString();
235
+ this.events.push({id, func});
236
+ return id;
237
+ }
238
+
239
+ removeEventSubscription(id){
240
+ const newEvents = this.events.filter(e => e.id === id);
241
+ this.events = newEvents;
242
+ }
243
+
244
+ publishEvent(eventName, data){
245
+ this.events.forEach(event => {
246
+ event.func(eventName, data)
247
+ });
248
+ }
249
+ static getOrCreate(configuration, name="default") {
250
+ return oidcFactory(configuration, name);
251
+ }
252
+ static get(name="default") {
253
+ return oidcDatabase[name];
254
+ }
255
+ static eventNames = eventNames;
256
+
257
+ silentSigninCallbackFromIFrame(){
258
+ if (this.configuration.silent_redirect_uri) {
259
+ window.top.postMessage(`${this.configurationName}_oidc_tokens:${JSON.stringify(this.tokens)}`, window.location.origin);
260
+ }
261
+ }
262
+ async silentSigninAsync() {
263
+ if (!this.configuration.silent_redirect_uri) {
264
+ return Promise.resolve(null);
265
+ }
266
+ this.publishEvent(eventNames.silentSigninAsync_begin, {});
267
+ const configuration = this.configuration
268
+ const link = configuration.silent_redirect_uri;
269
+ const iframe = document.createElement('iframe');
270
+ iframe.width = "0px";
271
+ iframe.height = "0px";
272
+ iframe.id = `${this.configurationName}_oidc_iframe`;
273
+ iframe.setAttribute("src", link);
274
+ document.body.appendChild(iframe);
275
+ const self = this;
276
+ const promise = new Promise((resolve, reject) => {
277
+ try {
278
+ let isResolved = false;
279
+ window.onmessage = function (e) {
280
+ const key = `${self.configurationName}_oidc_tokens:`;
281
+ if (e.data && typeof (e.data) === "string" && e.data.startsWith(key)) {
282
+
283
+ if (!isResolved) {
284
+ self.publishEvent(eventNames.silentSigninAsync_end, {});
285
+ resolve(JSON.parse(e.data.replace(key, '')));
286
+ iframe.remove();
287
+ isResolved = true;
288
+ }
289
+ }
290
+ };
291
+ const silentSigninTimeout = configuration.silent_signin_timeout ? configuration.silent_signin_timeout : 12000
292
+ setTimeout(() => {
293
+ if (!isResolved) {
294
+ reject("timeout");
295
+ self.publishEvent(eventNames.silentSigninAsync_error, new Error("timeout"));
296
+ iframe.remove();
297
+ isResolved = true;
298
+ }
299
+ }, silentSigninTimeout);
300
+ } catch (e) {
301
+ iframe.remove();
302
+ reject(e);
303
+ self.publishEvent(eventNames.silentSigninAsync_error, e);
304
+ }
305
+ });
306
+ return promise;
307
+ }
308
+ async initAsync(authority:string, authorityConfiguration:AuthorityConfiguration) {
309
+ if (authorityConfiguration != null) {
310
+ return new AuthorizationServiceConfiguration( {
311
+ authorization_endpoint: authorityConfiguration.authorization_endpoint,
312
+ end_session_endpoint: authorityConfiguration.end_session_endpoint,
313
+ revocation_endpoint: authorityConfiguration.revocation_endpoint,
314
+ token_endpoint: authorityConfiguration.token_endpoint,
315
+ userinfo_endpoint: authorityConfiguration.userinfo_endpoint});
316
+ }
317
+ return await AuthorizationServiceConfiguration.fetchFromIssuer(authority, new FetchRequestor());
318
+ }
319
+
320
+ async tryKeepExistingSessionAsync() {
321
+ let serviceWorker
322
+ if(this.tokens != null){
323
+ return false;
324
+ }
325
+ this.publishEvent(eventNames.tryKeepExistingSessionAsync_begin, {});
326
+ try {
327
+ const configuration = this.configuration;
328
+ const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
329
+ serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
330
+ if(serviceWorker) {
331
+ const { tokens } = await serviceWorker.initAsync(oidcServerConfiguration, "tryKeepExistingSessionAsync");
332
+ if (tokens) {
333
+ serviceWorker.startKeepAliveServiceWorker();
334
+ const updatedTokens = await this.refreshTokensAsync(tokens.refresh_token, true);
335
+ // @ts-ignore
336
+ this.tokens = await setTokensAsync(serviceWorker, updatedTokens);
337
+ this.serviceWorker = serviceWorker;
338
+ // @ts-ignore
339
+ this.timeoutId = await autoRenewTokensAsync(this, updatedTokens.refreshToken, this.tokens.expiresAt);
340
+ this.publishEvent(eventNames.tryKeepExistingSessionAsync_end, {success: true, message : "tokens inside ServiceWorker are valid"});
341
+ return true;
342
+ }
343
+ this.publishEvent(eventNames.tryKeepExistingSessionAsync_end, {success: false, message : "no exiting session found"});
344
+ } else {
345
+ if(configuration.service_worker_relative_url) {
346
+ this.publishEvent(eventNames.service_worker_not_supported_by_browser, {
347
+ message: "service worker is not supported by this browser"
348
+ });
349
+ }
350
+ const session = initSession(this.configurationName);
351
+ const {tokens} = await session.initAsync();
352
+ if (tokens) {
353
+ const updatedTokens = await this.refreshTokensAsync(tokens.refreshToken, true);
354
+ // @ts-ignore
355
+ this.tokens = await setTokensAsync(serviceWorker, updatedTokens);
356
+ session.setTokens(this.tokens);
357
+ this.session = session;
358
+ // @ts-ignore
359
+ this.timeoutId = await autoRenewTokensAsync(this, updatedTokens.refreshToken, this.tokens.expiresAt);
360
+ this.publishEvent(eventNames.tryKeepExistingSessionAsync_end, {success: true, message : "tokens inside ServiceWorker are valid"});
361
+ return true;
362
+ }
363
+ }
364
+ this.publishEvent(eventNames.tryKeepExistingSessionAsync_end, {success: false, message : "no service worker"});
365
+ return false;
366
+ } catch (exception) {
367
+ if(serviceWorker){
368
+ await serviceWorker.clearAsync();
369
+ }
370
+ this.publishEvent(eventNames.tryKeepExistingSessionAsync_error, "tokens inside ServiceWorker are invalid");
371
+ return false;
372
+ }
373
+ }
374
+
375
+ async loginAsync(callbackPath:string=undefined, extras:StringMap=null, installServiceWorker=true) {
376
+ try {
377
+ const location = window.location;
378
+ const url = callbackPath || location.pathname + (location.search || '') + (location.hash || '');
379
+ const state = url;
380
+ this.publishEvent(eventNames.loginAsync_begin, {});
381
+ const configuration = this.configuration
382
+ // Security we cannot loggin from Iframe
383
+ if (!configuration.silent_redirect_uri && isInIframe()) {
384
+ throw new Error("Login from iframe is forbidden");
385
+ }
386
+ let serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
387
+ const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
388
+ if(serviceWorker && installServiceWorker) {
389
+ const isServiceWorkerProxyActive = await serviceWorker.isServiceWorkerProxyActiveAsync()
390
+ if(!isServiceWorkerProxyActive) {
391
+ window.location.href = configuration.redirect_uri + "/service-worker-install?callbackPath=" + encodeURIComponent(url);
392
+ return;
393
+ }
394
+ }
395
+ let storage;
396
+ if(serviceWorker) {
397
+ serviceWorker.startKeepAliveServiceWorker();
398
+ await serviceWorker.initAsync(oidcServerConfiguration, "loginAsync");
399
+ storage = new MemoryStorageBackend(serviceWorker.saveItemsAsync, {});
400
+ } else {
401
+ const session = initSession(this.configurationName);
402
+ storage = new MemoryStorageBackend(session.saveItemsAsync, {});
403
+ }
404
+
405
+ // @ts-ignore
406
+ const authorizationHandler = new RedirectRequestHandler(storage, new NoHashQueryStringUtils(), window.location, new DefaultCrypto());
407
+ const authRequest = new AuthorizationRequest({
408
+ client_id: configuration.client_id,
409
+ redirect_uri: configuration.redirect_uri,
410
+ scope: configuration.scope,
411
+ response_type: AuthorizationRequest.RESPONSE_TYPE_CODE,
412
+ state,
413
+ extras: extras ?? configuration.extras
414
+ });
415
+ authorizationHandler.performAuthorizationRequest(oidcServerConfiguration, authRequest);
416
+ } catch(exception){
417
+ this.publishEvent(eventNames.loginAsync_error, exception);
418
+ throw exception;
419
+ }
420
+ }
421
+
422
+ async loginCallbackAsync() {
423
+ try {
424
+ this.publishEvent(eventNames.loginCallbackAsync_begin, {});
425
+ const configuration = this.configuration;
426
+ const clientId = configuration.client_id;
427
+ const redirectURL = configuration.redirect_uri;
428
+ const authority = configuration.authority;
429
+ const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
430
+ const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
431
+ let storage = null;
432
+ if(serviceWorker){
433
+ serviceWorker.startKeepAliveServiceWorker();
434
+ this.serviceWorker = serviceWorker;
435
+ await serviceWorker.initAsync(oidcServerConfiguration, "loginCallbackAsync");
436
+ const items = await serviceWorker.loadItemsAsync();
437
+ storage = new MemoryStorageBackend(serviceWorker.saveItemsAsync, items);
438
+ }else{
439
+ const session = initSession(this.configurationName);
440
+ this.session = session;
441
+ const items = await session.loadItemsAsync();
442
+ storage = new MemoryStorageBackend(session.saveItemsAsync, items);
443
+ }
444
+
445
+ const promise = new Promise((resolve, reject) => {
446
+ const tokenHandler = new BaseTokenRequestHandler(new FetchRequestor());
447
+ // @ts-ignore
448
+ const authorizationHandler = new RedirectRequestHandler(storage, new NoHashQueryStringUtils(), window.location, new DefaultCrypto());
449
+ const notifier = new AuthorizationNotifier();
450
+ authorizationHandler.setAuthorizationNotifier(notifier);
451
+
452
+ notifier.setAuthorizationListener(async (request, response, error) => {
453
+ if(error){
454
+ reject(error);
455
+ }
456
+ if (!response) {
457
+ return;
458
+ }
459
+
460
+ let extras = null;
461
+ if (request && request.internal) {
462
+ extras = {};
463
+ extras.code_verifier = request.internal.code_verifier;
464
+ if(configuration.token_request_extras) {
465
+ for (let [key, value] of Object.entries(configuration.token_request_extras)) {
466
+ extras[key] = value;
467
+ }
468
+ }
469
+ }
470
+
471
+ const tokenRequest = new TokenRequest({
472
+ client_id: clientId,
473
+ redirect_uri: redirectURL,
474
+ grant_type: GRANT_TYPE_AUTHORIZATION_CODE,
475
+ code: response.code,
476
+ refresh_token: undefined,
477
+ extras,
478
+ });
479
+
480
+ try {
481
+ const tokenResponse = await tokenHandler.performTokenRequest(oidcServerConfiguration, tokenRequest);
482
+ resolve({tokens:tokenResponse, state: request.state});
483
+ this.publishEvent(eventNames.loginCallbackAsync_end, {})
484
+ } catch(exception){
485
+ this.publishEvent(eventNames.loginCallbackAsync_error, exception);
486
+ console.error(exception);
487
+ reject(exception);
488
+ }
489
+ });
490
+ authorizationHandler.completeAuthorizationRequestIfPossible();
491
+ });
492
+ return promise;
493
+ } catch(exception) {
494
+ console.error(exception);
495
+ this.publishEvent(eventNames.loginCallbackAsync_error, exception);
496
+ throw exception;
497
+ }
498
+
499
+ }
500
+
501
+ async refreshTokensAsync(refreshToken, silentEvent = false) {
502
+ const localSilentSigninAsync= async (exception=null) => {
503
+ try {
504
+ const silent_token_response = await this.silentSigninAsync();
505
+ if (silent_token_response) {
506
+ return silent_token_response;
507
+ }
508
+ } catch (exceptionSilent) {
509
+ console.error(exceptionSilent);
510
+ }
511
+
512
+ this.publishEvent(silentEvent ? eventNames.refreshTokensAsync_silent_error : eventNames.refreshTokensAsync_error, exception);
513
+ return null;
514
+ }
515
+
516
+ try{
517
+ this.publishEvent(silentEvent ? eventNames.refreshTokensAsync_silent_begin : eventNames.refreshTokensAsync_begin, {})
518
+ const configuration = this.configuration;
519
+ const clientId = configuration.client_id;
520
+ const redirectUri = configuration.redirect_uri;
521
+ const authority = configuration.authority;
522
+
523
+ if(!configuration.scope.split(" ").find(s => s === refresh_token_scope))
524
+ {
525
+ return await localSilentSigninAsync();
526
+ }
527
+ const tokenHandler = new BaseTokenRequestHandler(new FetchRequestor());
528
+
529
+ let extras = undefined;
530
+ if(configuration.token_request_extras) {
531
+ extras = {}
532
+ for (let [key, value] of Object.entries(configuration.token_request_extras)) {
533
+ extras[key] = value;
534
+ }
535
+ }
536
+
537
+ // use the token response to make a request for an access token
538
+ const request = new TokenRequest({
539
+ client_id: clientId,
540
+ redirect_uri: redirectUri,
541
+ grant_type: GRANT_TYPE_REFRESH_TOKEN,
542
+ code: undefined,
543
+ refresh_token: refreshToken,
544
+ extras
545
+ });
546
+
547
+ const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
548
+ const token_response = await tokenHandler.performTokenRequest(oidcServerConfiguration, request);
549
+ this.publishEvent(silentEvent ? eventNames.refreshTokensAsync_silent_end :eventNames.refreshTokensAsync_end, token_response);
550
+ return token_response;
551
+ } catch(exception) {
552
+ console.error(exception);
553
+ return await localSilentSigninAsync(exception);
554
+ }
555
+ }
556
+
557
+ loginCallbackWithAutoTokensRenewAsync():Promise<string>{
558
+ return loginCallbackWithAutoTokensRenewAsync(this);
559
+ }
560
+
561
+ userInfoAsync(){
562
+ return userInfoAsync(this);
563
+ }
564
+
565
+ async destroyAsync() {
566
+ if(this.serviceWorker){
567
+ await this.serviceWorker.clearAsync();
568
+ }
569
+ if(this.session){
570
+ await this.session.clearAsync();
571
+ }
572
+ this.tokens = null;
573
+ this.userInfo = null;
574
+ this.events = [];
575
+ timer.clearTimeout(this.timeoutId);
576
+ }
577
+
578
+ async logoutAsync(callbackPath: string | undefined = undefined) {
579
+ const configuration = this.configuration;
580
+ const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
581
+ // TODO implement real logout
582
+ if(callbackPath && (typeof callbackPath !== 'string'))
583
+ {
584
+ callbackPath = undefined;
585
+ console.warn('callbackPath path is not a string');
586
+ }
587
+ const path = callbackPath || location.pathname + (location.search || '') + (location.hash || '');
588
+ const url = window.location.origin +path;
589
+ await this.destroyAsync();
590
+ if(oidcServerConfiguration.endSessionEndpoint) {
591
+ window.location.href = oidcServerConfiguration.endSessionEndpoint + "?redirect_uri=" + encodeURI(url);
592
+ }
593
+ else{
594
+ window.location.reload();
595
+ }
596
+ }
597
+ }
598
+
599
+
600
+ export default Oidc;