@inrupt/solid-client-authn-browser 1.17.1 → 1.17.3

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 (58) hide show
  1. package/dist/ClientAuthentication.d.ts +7 -0
  2. package/dist/Session.d.ts +174 -0
  3. package/dist/constant.d.ts +2 -2
  4. package/dist/defaultSession.d.ts +70 -0
  5. package/dist/dependencies.d.ts +12 -0
  6. package/dist/index.js +833 -34
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +833 -34
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/login/oidc/AggregateOidcHandler.d.ts +10 -0
  11. package/dist/login/oidc/AggregateRedirectHandler.d.ts +10 -0
  12. package/dist/login/oidc/ClientRegistrar.d.ts +7 -0
  13. package/dist/login/oidc/IssuerConfigFetcher.d.ts +10 -0
  14. package/dist/login/oidc/OidcLoginHandler.d.ts +10 -0
  15. package/dist/login/oidc/Redirector.d.ts +7 -0
  16. package/dist/login/oidc/incomingRedirectHandler/AuthCodeRedirectHandler.d.ts +3 -0
  17. package/dist/login/oidc/incomingRedirectHandler/ErrorOidcHandler.d.ts +10 -0
  18. package/dist/login/oidc/incomingRedirectHandler/FallbackRedirectHandler.d.ts +10 -0
  19. package/dist/login/oidc/oidcHandlers/AuthorizationCodeWithPkceOidcHandler.d.ts +12 -0
  20. package/dist/login/oidc/refresh/TokenRefresher.d.ts +7 -0
  21. package/dist/logout/buildRpInitiatedLogout.d.ts +7 -0
  22. package/dist/sessionInfo/SessionInfoManager.d.ts +18 -0
  23. package/dist/solid-client-authn.bundle.js +7 -7
  24. package/dist/solid-client-authn.bundle.js.map +1 -1
  25. package/dist/storage/BrowserStorage.d.ts +7 -0
  26. package/dist/storage/StorageUtility.d.ts +14 -0
  27. package/dist/util/UuidGenerator.d.ts +6 -0
  28. package/package.json +8 -8
  29. package/rollup.config.mjs +1 -1
  30. package/src/ClientAuthentication.spec.ts +106 -57
  31. package/src/ClientAuthentication.ts +18 -7
  32. package/src/Session.spec.ts +51 -54
  33. package/src/Session.ts +24 -18
  34. package/src/__mocks__/ClientAuthentication.ts +2 -2
  35. package/src/defaultSession.ts +4 -3
  36. package/src/dependencies.ts +5 -5
  37. package/src/login/oidc/ClientRegistrar.spec.ts +22 -22
  38. package/src/login/oidc/ClientRegistrar.ts +4 -2
  39. package/src/login/oidc/IssuerConfigFetcher.spec.ts +25 -25
  40. package/src/login/oidc/IssuerConfigFetcher.ts +8 -6
  41. package/src/login/oidc/OidcLoginHandler.spec.ts +15 -15
  42. package/src/login/oidc/OidcLoginHandler.ts +14 -9
  43. package/src/login/oidc/Redirector.spec.ts +1 -1
  44. package/src/login/oidc/__mocks__/ClientRegistrar.ts +3 -3
  45. package/src/login/oidc/__mocks__/IssuerConfigFetcher.ts +3 -3
  46. package/src/login/oidc/incomingRedirectHandler/AuthCodeRedirectHandler.spec.ts +42 -42
  47. package/src/login/oidc/incomingRedirectHandler/AuthCodeRedirectHandler.ts +19 -13
  48. package/src/login/oidc/incomingRedirectHandler/ErrorOidcHandler.spec.ts +12 -12
  49. package/src/login/oidc/incomingRedirectHandler/ErrorOidcHandler.ts +2 -2
  50. package/src/login/oidc/incomingRedirectHandler/FallbackRedirectHandler.spec.ts +7 -7
  51. package/src/login/oidc/incomingRedirectHandler/FallbackRedirectHandler.ts +2 -2
  52. package/src/login/oidc/oidcHandlers/AuthorizationCodeWithPkceOidcHandler.spec.ts +17 -17
  53. package/src/login/oidc/refresh/TokenRefresher.spec.ts +14 -14
  54. package/src/login/oidc/refresh/TokenRefresher.ts +12 -8
  55. package/src/login/oidc/refresh/__mocks__/TokenRefresher.ts +1 -1
  56. package/src/sessionInfo/SessionInfoManager.spec.ts +37 -15
  57. package/src/sessionInfo/SessionInfoManager.ts +46 -50
  58. package/src/sessionInfo/__mocks__/SessionInfoManager.ts +3 -3
package/dist/index.mjs CHANGED
@@ -5,29 +5,98 @@ import EventEmitter from 'events';
5
5
  import { removeOidcQueryParam, OidcClient, clearOidcPersistentStorage, getDpopToken, getBearerToken, registerClient, refresh } from '@inrupt/oidc-client-ext';
6
6
  import { fetch as fetch$1 } from '@inrupt/universal-fetch';
7
7
 
8
+ //
9
+ // Copyright Inrupt Inc.
10
+ //
11
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ // of this software and associated documentation files (the "Software"), to deal in
13
+ // the Software without restriction, including without limitation the rights to use,
14
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
15
+ // Software, and to permit persons to whom the Software is furnished to do so,
16
+ // subject to the following conditions:
17
+ //
18
+ // The above copyright notice and this permission notice shall be included in
19
+ // all copies or substantial portions of the Software.
20
+ //
21
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
22
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
23
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+ //
28
+ /**
29
+ * This class in a no-value-added extension of StorageUtility from the core module.
30
+ * The reason it has to be declared is for TSyringe to find the decorators in the
31
+ * same modules as where the dependency container is declared (in this case,
32
+ * the browser module, with the dependancy container in dependencies.ts).
33
+ * @hidden
34
+ */
8
35
  class StorageUtilityBrowser extends StorageUtility {
9
36
  constructor(secureStorage, insecureStorage) {
10
37
  super(secureStorage, insecureStorage);
11
38
  }
12
39
  }
13
40
 
41
+ //
42
+ // Copyright Inrupt Inc.
43
+ //
44
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
45
+ // of this software and associated documentation files (the "Software"), to deal in
46
+ // the Software without restriction, including without limitation the rights to use,
47
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
48
+ // Software, and to permit persons to whom the Software is furnished to do so,
49
+ // subject to the following conditions:
50
+ //
51
+ // The above copyright notice and this permission notice shall be included in
52
+ // all copies or substantial portions of the Software.
53
+ //
54
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
55
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
56
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
57
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
58
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
59
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
60
+ //
61
+ /**
62
+ * @hidden
63
+ */
14
64
  class ClientAuthentication extends ClientAuthentication$1 {
15
65
  constructor() {
16
66
  super(...arguments);
67
+ // Define these functions as properties so that they don't get accidentally re-bound.
68
+ // Isn't Javascript fun?
17
69
  this.login = async (options, eventEmitter) => {
18
70
  var _a, _b;
71
+ // In order to get a clean start, make sure that the session is logged out
72
+ // on login.
73
+ // But we may want to preserve our client application info, particularly if
74
+ // we used Dynamic Client Registration to register (since we don't
75
+ // necessarily want the user to have to register this app each time they
76
+ // login).
19
77
  await this.sessionInfoManager.clear(options.sessionId);
78
+ // In the case of the user hitting the 'back' button in their browser, they
79
+ // could return to a previous redirect URL that contains OIDC params that
80
+ // are now longer valid. To be safe, strip relevant params now.
81
+ // If the user is providing a redirect IRI, it should not be modified, so
82
+ // normalization only applies if we default to the current location (which is
83
+ // a bad practice and should be discouraged).
20
84
  const redirectUrl = (_a = options.redirectUrl) !== null && _a !== void 0 ? _a : removeOidcQueryParam(window.location.href);
21
85
  if (!isValidRedirectUrl(redirectUrl)) {
22
- throw new Error(`${redirectUrl} is not a valid redirect URL, it is either a malformed IRI or it includes a hash fragment.`);
86
+ throw new Error(`${redirectUrl} is not a valid redirect URL, it is either a malformed IRI, includes a hash fragment, or reserved query parameters ('code' or 'state').`);
23
87
  }
24
88
  await this.loginHandler.handle({
25
89
  ...options,
26
90
  redirectUrl,
91
+ // If no clientName is provided, the clientId may be used instead.
27
92
  clientName: (_b = options.clientName) !== null && _b !== void 0 ? _b : options.clientId,
28
93
  eventEmitter,
29
94
  });
30
95
  };
96
+ // Collects session information from storage, and returns them. Returns null
97
+ // if the expected information cannot be found.
98
+ // Note that the ID token is not stored, which means the session information
99
+ // cannot be validated at this point.
31
100
  this.validateCurrentSession = async (currentSessionId) => {
32
101
  const sessionInfo = await this.sessionInfoManager.get(currentSessionId);
33
102
  if (sessionInfo === undefined ||
@@ -40,9 +109,14 @@ class ClientAuthentication extends ClientAuthentication$1 {
40
109
  this.handleIncomingRedirect = async (url, eventEmitter) => {
41
110
  try {
42
111
  const redirectInfo = await this.redirectHandler.handle(url, eventEmitter);
112
+ // The `FallbackRedirectHandler` directly returns the global `fetch` for
113
+ // his value, so we should ensure it's bound to `window` rather than to
114
+ // ClientAuthentication, to avoid the following error:
115
+ // > 'fetch' called on an object that does not implement interface Window.
43
116
  this.fetch = redirectInfo.fetch.bind(window);
44
117
  this.boundLogout = redirectInfo.getLogoutUrl;
45
- this.cleanUrlAfterRedirect(url);
118
+ // Strip the oauth params:
119
+ await this.cleanUrlAfterRedirect(url);
46
120
  return {
47
121
  isLoggedIn: redirectInfo.isLoggedIn,
48
122
  webId: redirectInfo.webId,
@@ -51,37 +125,89 @@ class ClientAuthentication extends ClientAuthentication$1 {
51
125
  };
52
126
  }
53
127
  catch (err) {
54
- this.cleanUrlAfterRedirect(url);
128
+ // Strip the oauth params:
129
+ await this.cleanUrlAfterRedirect(url);
130
+ // FIXME: EVENTS.ERROR should be errorCode, errorDescription
131
+ //
132
+ // I'm not sure if "redirect" is a good error code, and in theory `err`
133
+ // maybe an Error object and not a string; Maybe we want to just hardcode
134
+ // a description instead?
55
135
  eventEmitter.emit(EVENTS.ERROR, "redirect", err);
56
136
  return undefined;
57
137
  }
58
138
  };
59
139
  }
60
- cleanUrlAfterRedirect(url) {
140
+ async cleanUrlAfterRedirect(url) {
61
141
  const cleanedUpUrl = new URL(url);
62
142
  cleanedUpUrl.searchParams.delete("state");
143
+ // For auth code flow
63
144
  cleanedUpUrl.searchParams.delete("code");
145
+ // For implicit flow
64
146
  cleanedUpUrl.searchParams.delete("id_token");
65
147
  cleanedUpUrl.searchParams.delete("access_token");
148
+ // For login error
66
149
  cleanedUpUrl.searchParams.delete("error");
67
150
  cleanedUpUrl.searchParams.delete("error_description");
68
151
  cleanedUpUrl.searchParams.delete("iss");
152
+ // Remove OAuth-specific query params (since the login flow finishes with
153
+ // the browser being redirected back with OAuth2 query params (e.g. for
154
+ // 'code' and 'state'), and so if the user simply refreshes this page our
155
+ // authentication library will be called again with what are now invalid
156
+ // query parameters!).
69
157
  window.history.replaceState(null, "", cleanedUpUrl.toString());
158
+ while (window.location.href !== cleanedUpUrl.href) {
159
+ // Poll the current URL every ms. Active polling is required because
160
+ // window.history.replaceState is asynchronous, but the associated
161
+ // 'popstate' event which should be listened to is only sent on active
162
+ // navigation, which we will not have here.
163
+ // See https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event#when_popstate_is_sent
164
+ // eslint-disable-next-line no-await-in-loop
165
+ await new Promise((resolve) => {
166
+ setTimeout(() => resolve(), 1);
167
+ });
168
+ }
70
169
  }
71
170
  }
72
171
 
172
+ //
173
+ // Copyright Inrupt Inc.
174
+ //
175
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
176
+ // of this software and associated documentation files (the "Software"), to deal in
177
+ // the Software without restriction, including without limitation the rights to use,
178
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
179
+ // Software, and to permit persons to whom the Software is furnished to do so,
180
+ // subject to the following conditions:
181
+ //
182
+ // The above copyright notice and this permission notice shall be included in
183
+ // all copies or substantial portions of the Software.
184
+ //
185
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
186
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
187
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
188
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
189
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
190
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
191
+ //
73
192
  function hasIssuer(options) {
74
193
  return typeof options.oidcIssuer === "string";
75
194
  }
76
195
  function hasRedirectUrl(options) {
77
196
  return typeof options.redirectUrl === "string";
78
197
  }
198
+ /**
199
+ * @hidden
200
+ */
79
201
  class OidcLoginHandler {
80
202
  constructor(storageUtility, oidcHandler, issuerConfigFetcher, clientRegistrar) {
81
203
  this.storageUtility = storageUtility;
82
204
  this.oidcHandler = oidcHandler;
83
205
  this.issuerConfigFetcher = issuerConfigFetcher;
84
206
  this.clientRegistrar = clientRegistrar;
207
+ this.storageUtility = storageUtility;
208
+ this.oidcHandler = oidcHandler;
209
+ this.issuerConfigFetcher = issuerConfigFetcher;
210
+ this.clientRegistrar = clientRegistrar;
85
211
  }
86
212
  async canHandle(options) {
87
213
  return hasIssuer(options) && hasRedirectUrl(options);
@@ -93,22 +219,57 @@ class OidcLoginHandler {
93
219
  if (!hasRedirectUrl(options)) {
94
220
  throw new ConfigurationError(`OidcLoginHandler requires a redirect URL: missing property 'redirectUrl' in ${JSON.stringify(options)}`);
95
221
  }
222
+ // Fetch issuer config.
96
223
  const issuerConfig = await this.issuerConfigFetcher.fetchConfig(options.oidcIssuer);
97
224
  const clientRegistration = await handleRegistration(options, issuerConfig, this.storageUtility, this.clientRegistrar);
225
+ // Construct OIDC Options
98
226
  const OidcOptions = {
227
+ // Note that here, the issuer is not the one from the received options, but
228
+ // from the issuer's config. This enforces the canonical URL is used and stored,
229
+ // which is also the one present in the ID token, so storing a technically
230
+ // valid, but different issuer URL (e.g. using a trailing slash or not) now
231
+ // could prevent from validating the ID token later.
99
232
  issuer: issuerConfig.issuer,
233
+ // TODO: differentiate if DPoP should be true
100
234
  dpop: options.tokenType.toLowerCase() === "dpop",
101
235
  ...options,
102
236
  issuerConfiguration: issuerConfig,
103
237
  client: clientRegistration,
104
238
  };
239
+ // Call proper OIDC Handler
105
240
  return this.oidcHandler.handle(OidcOptions);
106
241
  }
107
242
  }
108
243
 
244
+ //
245
+ // Copyright Inrupt Inc.
246
+ //
247
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
248
+ // of this software and associated documentation files (the "Software"), to deal in
249
+ // the Software without restriction, including without limitation the rights to use,
250
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
251
+ // Software, and to permit persons to whom the Software is furnished to do so,
252
+ // subject to the following conditions:
253
+ //
254
+ // The above copyright notice and this permission notice shall be included in
255
+ // all copies or substantial portions of the Software.
256
+ //
257
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
258
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
259
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
260
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
261
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
262
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
263
+ //
264
+ /**
265
+ * @hidden
266
+ * Authorization code flow spec: https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
267
+ * PKCE: https://tools.ietf.org/html/rfc7636
268
+ */
109
269
  class AuthorizationCodeWithPkceOidcHandler extends AuthorizationCodeWithPkceOidcHandlerBase {
110
270
  async handle(oidcLoginOptions) {
111
271
  var _a;
272
+ /* eslint-disable camelcase */
112
273
  const oidcOptions = {
113
274
  authority: oidcLoginOptions.issuer.toString(),
114
275
  client_id: oidcLoginOptions.client.clientId,
@@ -118,28 +279,58 @@ class AuthorizationCodeWithPkceOidcHandler extends AuthorizationCodeWithPkceOidc
118
279
  response_type: "code",
119
280
  scope: DEFAULT_SCOPES,
120
281
  filterProtocolClaims: true,
282
+ // The userinfo endpoint on NSS fails, so disable this for now
283
+ // Note that in Solid, information should be retrieved from the
284
+ // profile referenced by the WebId.
121
285
  loadUserInfo: false,
122
286
  code_verifier: true,
123
287
  prompt: (_a = oidcLoginOptions.prompt) !== null && _a !== void 0 ? _a : "consent",
124
288
  };
289
+ /* eslint-enable camelcase */
125
290
  const oidcClientLibrary = new OidcClient(oidcOptions);
126
291
  try {
127
292
  const signingRequest = await oidcClientLibrary.createSigninRequest();
293
+ // Make sure to await the promise before returning so that the error is caught.
128
294
  return await this.handleRedirect({
129
295
  oidcLoginOptions,
296
+ // eslint-disable-next-line no-underscore-dangle
130
297
  state: signingRequest.state._id,
298
+ // eslint-disable-next-line no-underscore-dangle
131
299
  codeVerifier: signingRequest.state._code_verifier,
132
300
  targetUrl: signingRequest.url.toString(),
133
301
  });
134
302
  }
135
303
  catch (err) {
304
+ // eslint-disable-next-line no-console
136
305
  console.error(err);
137
306
  }
307
+ // The login is only completed AFTER redirect, so nothing to return here.
138
308
  return undefined;
139
309
  }
140
310
  }
141
311
 
312
+ //
313
+ // Copyright Inrupt Inc.
314
+ //
315
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
316
+ // of this software and associated documentation files (the "Software"), to deal in
317
+ // the Software without restriction, including without limitation the rights to use,
318
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
319
+ // Software, and to permit persons to whom the Software is furnished to do so,
320
+ // subject to the following conditions:
321
+ //
322
+ // The above copyright notice and this permission notice shall be included in
323
+ // all copies or substantial portions of the Software.
324
+ //
325
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
326
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
327
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
328
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
329
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
330
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
331
+ //
142
332
  const WELL_KNOWN_OPENID_CONFIG = ".well-known/openid-configuration";
333
+ /* eslint-disable camelcase */
143
334
  const issuerConfigKeyMap = {
144
335
  issuer: {
145
336
  toKey: "issuer",
@@ -227,10 +418,15 @@ const issuerConfigKeyMap = {
227
418
  convertToUrl: true,
228
419
  },
229
420
  };
421
+ /* eslint-enable camelcase */
230
422
  function processConfig(config) {
231
423
  const parsedConfig = {};
232
424
  Object.keys(config).forEach((key) => {
233
425
  if (issuerConfigKeyMap[key]) {
426
+ // TODO: PMcB55: Validate URL if "issuerConfigKeyMap[key].convertToUrl"
427
+ // if (issuerConfigKeyMap[key].convertToUrl) {
428
+ // validateUrl(config[key]);
429
+ // }
234
430
  parsedConfig[issuerConfigKeyMap[key].toKey] = config[key];
235
431
  }
236
432
  });
@@ -239,60 +435,110 @@ function processConfig(config) {
239
435
  }
240
436
  return parsedConfig;
241
437
  }
438
+ /**
439
+ * @hidden
440
+ */
242
441
  class IssuerConfigFetcher {
243
442
  constructor(storageUtility) {
244
443
  this.storageUtility = storageUtility;
444
+ this.storageUtility = storageUtility;
245
445
  }
446
+ // This method needs no state (so can be static), and can be exposed to allow
447
+ // callers to know where this implementation puts state it needs.
246
448
  static getLocalStorageKey(issuer) {
247
449
  return `issuerConfig:${issuer}`;
248
450
  }
249
451
  async fetchConfig(issuer) {
250
452
  let issuerConfig;
251
- const openIdConfigUrl = new URL(WELL_KNOWN_OPENID_CONFIG, issuer.endsWith("/") ? issuer : `${issuer}/`).href;
453
+ const openIdConfigUrl = new URL(WELL_KNOWN_OPENID_CONFIG,
454
+ // Make sure to append a slash at issuer URL, so that the .well-known URL
455
+ // includes the full issuer path. See https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig.
456
+ issuer.endsWith("/") ? issuer : `${issuer}/`).href;
252
457
  const issuerConfigRequestBody = await fetch$1.call(globalThis, openIdConfigUrl);
458
+ // Check the validity of the fetched config
253
459
  try {
254
460
  issuerConfig = processConfig(await issuerConfigRequestBody.json());
255
461
  }
256
462
  catch (err) {
257
463
  throw new ConfigurationError(`[${issuer.toString()}] has an invalid configuration: ${err.message}`);
258
464
  }
465
+ // Update store with fetched config
259
466
  await this.storageUtility.set(IssuerConfigFetcher.getLocalStorageKey(issuer), JSON.stringify(issuerConfig));
260
467
  return issuerConfig;
261
468
  }
262
469
  }
263
470
 
471
+ //
472
+ // Copyright Inrupt Inc.
473
+ //
474
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
475
+ // of this software and associated documentation files (the "Software"), to deal in
476
+ // the Software without restriction, including without limitation the rights to use,
477
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
478
+ // Software, and to permit persons to whom the Software is furnished to do so,
479
+ // subject to the following conditions:
480
+ //
481
+ // The above copyright notice and this permission notice shall be included in
482
+ // all copies or substantial portions of the Software.
483
+ //
484
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
485
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
486
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
487
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
488
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
489
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
490
+ //
491
+ /**
492
+ * @param sessionId
493
+ * @param storage
494
+ * @hidden
495
+ */
264
496
  async function clear(sessionId, storage) {
265
497
  await clear$1(sessionId, storage);
266
498
  await clearOidcPersistentStorage();
267
499
  }
500
+ /**
501
+ * @hidden
502
+ */
268
503
  class SessionInfoManager extends SessionInfoManagerBase {
269
504
  async get(sessionId) {
270
- var _a;
271
- const isLoggedIn = await this.storageUtility.getForUser(sessionId, "isLoggedIn", {
272
- secure: true,
273
- });
274
- const webId = await this.storageUtility.getForUser(sessionId, "webId", {
275
- secure: true,
276
- });
277
- const clientId = await this.storageUtility.getForUser(sessionId, "clientId", {
278
- secure: false,
279
- });
280
- const clientSecret = await this.storageUtility.getForUser(sessionId, "clientSecret", {
281
- secure: false,
282
- });
283
- const redirectUrl = await this.storageUtility.getForUser(sessionId, "redirectUrl", {
284
- secure: false,
285
- });
286
- const refreshToken = await this.storageUtility.getForUser(sessionId, "refreshToken", {
287
- secure: true,
288
- });
289
- const issuer = await this.storageUtility.getForUser(sessionId, "issuer", {
290
- secure: false,
291
- });
292
- const tokenType = (_a = (await this.storageUtility.getForUser(sessionId, "tokenType", {
293
- secure: false,
294
- }))) !== null && _a !== void 0 ? _a : "DPoP";
295
- if (!isSupportedTokenType(tokenType)) {
505
+ const [isLoggedIn, webId, clientId, clientSecret, redirectUrl, refreshToken, issuer, tokenType,] = await Promise.all([
506
+ this.storageUtility.getForUser(sessionId, "isLoggedIn", {
507
+ secure: true,
508
+ }),
509
+ this.storageUtility.getForUser(sessionId, "webId", {
510
+ secure: true,
511
+ }),
512
+ this.storageUtility.getForUser(sessionId, "clientId", {
513
+ secure: false,
514
+ }),
515
+ this.storageUtility.getForUser(sessionId, "clientSecret", {
516
+ secure: false,
517
+ }),
518
+ this.storageUtility.getForUser(sessionId, "redirectUrl", {
519
+ secure: false,
520
+ }),
521
+ this.storageUtility.getForUser(sessionId, "refreshToken", {
522
+ secure: true,
523
+ }),
524
+ this.storageUtility.getForUser(sessionId, "issuer", {
525
+ secure: false,
526
+ }),
527
+ this.storageUtility.getForUser(sessionId, "tokenType", {
528
+ secure: false,
529
+ }),
530
+ ]);
531
+ if (typeof redirectUrl === "string" && !isValidRedirectUrl(redirectUrl)) {
532
+ // This resolves the issue for people experiencing https://github.com/inrupt/solid-client-authn-js/issues/2891.
533
+ // An invalid redirect URL is present in the storage, and the session should
534
+ // be cleared to get a fresh start. This will require the user to log back in.
535
+ await Promise.all([
536
+ this.storageUtility.deleteAllUserData(sessionId, { secure: false }),
537
+ this.storageUtility.deleteAllUserData(sessionId, { secure: true }),
538
+ ]);
539
+ return undefined;
540
+ }
541
+ if (tokenType !== undefined && !isSupportedTokenType(tokenType)) {
296
542
  throw new Error(`Tokens of type [${tokenType}] are not supported.`);
297
543
  }
298
544
  if (clientId === undefined &&
@@ -310,17 +556,52 @@ class SessionInfoManager extends SessionInfoManagerBase {
310
556
  issuer,
311
557
  clientAppId: clientId,
312
558
  clientAppSecret: clientSecret,
313
- tokenType,
559
+ // Default the token type to DPoP if unspecified.
560
+ tokenType: tokenType !== null && tokenType !== void 0 ? tokenType : "DPoP",
314
561
  };
315
562
  }
563
+ /**
564
+ * This function removes all session-related information from storage.
565
+ * @param sessionId the session identifier
566
+ * @param storage the storage where session info is stored
567
+ * @hidden
568
+ */
316
569
  async clear(sessionId) {
317
570
  return clear(sessionId, this.storageUtility);
318
571
  }
319
572
  }
320
573
 
574
+ //
575
+ // Copyright Inrupt Inc.
576
+ //
577
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
578
+ // of this software and associated documentation files (the "Software"), to deal in
579
+ // the Software without restriction, including without limitation the rights to use,
580
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
581
+ // Software, and to permit persons to whom the Software is furnished to do so,
582
+ // subject to the following conditions:
583
+ //
584
+ // The above copyright notice and this permission notice shall be included in
585
+ // all copies or substantial portions of the Software.
586
+ //
587
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
588
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
589
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
590
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
591
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
592
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
593
+ //
594
+ /**
595
+ * This class handles redirect IRIs without any query params, and returns an unauthenticated
596
+ * session. It serves as a fallback so that consuming libraries don't have to test
597
+ * for the query params themselves, and can always try to use them as a redirect IRI.
598
+ * @hidden
599
+ */
321
600
  class FallbackRedirectHandler {
322
601
  async canHandle(redirectUrl) {
323
602
  try {
603
+ // The next URL object is built for validating it.
604
+ // eslint-disable-next-line no-new
324
605
  new URL(redirectUrl);
325
606
  return true;
326
607
  }
@@ -328,12 +609,44 @@ class FallbackRedirectHandler {
328
609
  throw new Error(`[${redirectUrl}] is not a valid URL, and cannot be used as a redirect URL: ${e}`);
329
610
  }
330
611
  }
331
- async handle(_redirectUrl) {
612
+ async handle(
613
+ // The argument is ignored, but must be present to implement the interface
614
+ _redirectUrl) {
332
615
  return getUnauthenticatedSession();
333
616
  }
334
617
  }
335
618
 
619
+ //
620
+ // Copyright Inrupt Inc.
621
+ //
622
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
623
+ // of this software and associated documentation files (the "Software"), to deal in
624
+ // the Software without restriction, including without limitation the rights to use,
625
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
626
+ // Software, and to permit persons to whom the Software is furnished to do so,
627
+ // subject to the following conditions:
628
+ //
629
+ // The above copyright notice and this permission notice shall be included in
630
+ // all copies or substantial portions of the Software.
631
+ //
632
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
633
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
634
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
635
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
636
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
637
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
638
+ //
639
+ /**
640
+ * @hidden
641
+ * @packageDocumentation
642
+ */
643
+ // FIXME: The following doesn't work in the browser, it results in all the fetches
644
+ // being unauthenticated. This should be looked into when migrating to universal-fetch.
645
+ // import { fetch } from "cross-fetch";
336
646
  const globalFetch = (...args) => fetch$1.call(globalThis, ...args);
647
+ /**
648
+ * @hidden
649
+ */
337
650
  class AuthCodeRedirectHandler {
338
651
  constructor(storageUtility, sessionInfoManager, issuerConfigFetcher, clientRegistrar, tokerRefresher) {
339
652
  this.storageUtility = storageUtility;
@@ -341,6 +654,11 @@ class AuthCodeRedirectHandler {
341
654
  this.issuerConfigFetcher = issuerConfigFetcher;
342
655
  this.clientRegistrar = clientRegistrar;
343
656
  this.tokerRefresher = tokerRefresher;
657
+ this.storageUtility = storageUtility;
658
+ this.sessionInfoManager = sessionInfoManager;
659
+ this.issuerConfigFetcher = issuerConfigFetcher;
660
+ this.clientRegistrar = clientRegistrar;
661
+ this.tokerRefresher = tokerRefresher;
344
662
  }
345
663
  async canHandle(redirectUrl) {
346
664
  try {
@@ -378,10 +696,15 @@ class AuthCodeRedirectHandler {
378
696
  if (isDpop) {
379
697
  tokens = await getDpopToken(issuerConfig, client, {
380
698
  grantType: "authorization_code",
699
+ // We rely on our 'canHandle' function checking that the OAuth 'code'
700
+ // parameter is present in our query string.
381
701
  code: url.searchParams.get("code"),
382
702
  codeVerifier,
383
703
  redirectUrl: storedRedirectIri,
384
704
  });
705
+ // Delete oidc-client-specific session information from storage. This is
706
+ // done automatically when retrieving a bearer token, but since the DPoP
707
+ // binding uses our custom code, this needs to be done manually.
385
708
  window.localStorage.removeItem(`oidc.${oauthState}`);
386
709
  }
387
710
  else {
@@ -422,12 +745,58 @@ class AuthCodeRedirectHandler {
422
745
  }
423
746
  }
424
747
 
748
+ //
749
+ // Copyright Inrupt Inc.
750
+ //
751
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
752
+ // of this software and associated documentation files (the "Software"), to deal in
753
+ // the Software without restriction, including without limitation the rights to use,
754
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
755
+ // Software, and to permit persons to whom the Software is furnished to do so,
756
+ // subject to the following conditions:
757
+ //
758
+ // The above copyright notice and this permission notice shall be included in
759
+ // all copies or substantial portions of the Software.
760
+ //
761
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
762
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
763
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
764
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
765
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
766
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
767
+ //
768
+ /**
769
+ * @hidden
770
+ */
425
771
  class AggregateRedirectHandler extends AggregateHandler {
426
772
  constructor(redirectHandlers) {
427
773
  super(redirectHandlers);
428
774
  }
429
775
  }
430
776
 
777
+ //
778
+ // Copyright Inrupt Inc.
779
+ //
780
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
781
+ // of this software and associated documentation files (the "Software"), to deal in
782
+ // the Software without restriction, including without limitation the rights to use,
783
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
784
+ // Software, and to permit persons to whom the Software is furnished to do so,
785
+ // subject to the following conditions:
786
+ //
787
+ // The above copyright notice and this permission notice shall be included in
788
+ // all copies or substantial portions of the Software.
789
+ //
790
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
791
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
792
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
793
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
794
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
795
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
796
+ //
797
+ /**
798
+ * @hidden
799
+ */
431
800
  class BrowserStorage {
432
801
  get storage() {
433
802
  return window.localStorage;
@@ -443,6 +812,29 @@ class BrowserStorage {
443
812
  }
444
813
  }
445
814
 
815
+ //
816
+ // Copyright Inrupt Inc.
817
+ //
818
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
819
+ // of this software and associated documentation files (the "Software"), to deal in
820
+ // the Software without restriction, including without limitation the rights to use,
821
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
822
+ // Software, and to permit persons to whom the Software is furnished to do so,
823
+ // subject to the following conditions:
824
+ //
825
+ // The above copyright notice and this permission notice shall be included in
826
+ // all copies or substantial portions of the Software.
827
+ //
828
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
829
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
830
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
831
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
832
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
833
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
834
+ //
835
+ /**
836
+ * @hidden
837
+ */
446
838
  class Redirector {
447
839
  redirect(redirectUrl, options) {
448
840
  if (options && options.handleRedirect) {
@@ -457,18 +849,49 @@ class Redirector {
457
849
  }
458
850
  }
459
851
 
852
+ //
853
+ // Copyright Inrupt Inc.
854
+ //
855
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
856
+ // of this software and associated documentation files (the "Software"), to deal in
857
+ // the Software without restriction, including without limitation the rights to use,
858
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
859
+ // Software, and to permit persons to whom the Software is furnished to do so,
860
+ // subject to the following conditions:
861
+ //
862
+ // The above copyright notice and this permission notice shall be included in
863
+ // all copies or substantial portions of the Software.
864
+ //
865
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
866
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
867
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
868
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
869
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
870
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
871
+ //
872
+ /**
873
+ * @hidden
874
+ */
460
875
  class ClientRegistrar {
461
876
  constructor(storageUtility) {
462
877
  this.storageUtility = storageUtility;
878
+ this.storageUtility = storageUtility;
463
879
  }
464
880
  async getClient(options, issuerConfig) {
465
- const [storedClientId, storedClientSecret,] = await Promise.all([
881
+ // If client secret and/or client id are stored in storage, use those.
882
+ const [storedClientId, storedClientSecret,
883
+ // storedClientName,
884
+ ] = await Promise.all([
466
885
  this.storageUtility.getForUser(options.sessionId, "clientId", {
467
886
  secure: false,
468
887
  }),
469
888
  this.storageUtility.getForUser(options.sessionId, "clientSecret", {
470
889
  secure: false,
471
890
  }),
891
+ // this.storageUtility.getForUser(options.sessionId, "clientName", {
892
+ // // FIXME: figure out how to persist secure storage at reload
893
+ // secure: false,
894
+ // }),
472
895
  ]);
473
896
  if (storedClientId) {
474
897
  return {
@@ -479,6 +902,7 @@ class ClientRegistrar {
479
902
  }
480
903
  try {
481
904
  const registeredClient = await registerClient(options, issuerConfig);
905
+ // Save info
482
906
  const infoToSave = {
483
907
  clientId: registeredClient.clientId,
484
908
  };
@@ -490,6 +914,9 @@ class ClientRegistrar {
490
914
  registeredClient.idTokenSignedResponseAlg;
491
915
  }
492
916
  await this.storageUtility.setForUser(options.sessionId, infoToSave, {
917
+ // FIXME: figure out how to persist secure storage at reload
918
+ // Otherwise, the client info cannot be retrieved from storage, and
919
+ // the lib tries to re-register the client on each fetch
493
920
  secure: false,
494
921
  });
495
922
  return registeredClient;
@@ -500,9 +927,36 @@ class ClientRegistrar {
500
927
  }
501
928
  }
502
929
 
930
+ //
931
+ // Copyright Inrupt Inc.
932
+ //
933
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
934
+ // of this software and associated documentation files (the "Software"), to deal in
935
+ // the Software without restriction, including without limitation the rights to use,
936
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
937
+ // Software, and to permit persons to whom the Software is furnished to do so,
938
+ // subject to the following conditions:
939
+ //
940
+ // The above copyright notice and this permission notice shall be included in
941
+ // all copies or substantial portions of the Software.
942
+ //
943
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
944
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
945
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
946
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
947
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
948
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
949
+ //
950
+ /**
951
+ * This class handles redirect IRIs without any query params, and returns an unauthenticated
952
+ * session. It serves as a fallback so that consuming libraries don't have to test
953
+ * for the query params themselves, and can always try to use them as a redirect IRI.
954
+ * @hidden
955
+ */
503
956
  class ErrorOidcHandler {
504
957
  async canHandle(redirectUrl) {
505
958
  try {
959
+ // eslint-disable-next-line no-new
506
960
  return new URL(redirectUrl).searchParams.has("error");
507
961
  }
508
962
  catch (e) {
@@ -520,16 +974,47 @@ class ErrorOidcHandler {
520
974
  }
521
975
  }
522
976
 
977
+ //
978
+ // Copyright Inrupt Inc.
979
+ //
980
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
981
+ // of this software and associated documentation files (the "Software"), to deal in
982
+ // the Software without restriction, including without limitation the rights to use,
983
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
984
+ // Software, and to permit persons to whom the Software is furnished to do so,
985
+ // subject to the following conditions:
986
+ //
987
+ // The above copyright notice and this permission notice shall be included in
988
+ // all copies or substantial portions of the Software.
989
+ //
990
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
991
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
992
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
993
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
994
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
995
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
996
+ //
997
+ // Some identifiers are not in camelcase on purpose, as they are named using the
998
+ // official names from the OIDC/OAuth2 specifications.
999
+ /* eslint-disable camelcase */
1000
+ /**
1001
+ * @hidden
1002
+ */
523
1003
  class TokenRefresher {
524
1004
  constructor(storageUtility, issuerConfigFetcher, clientRegistrar) {
525
1005
  this.storageUtility = storageUtility;
526
1006
  this.issuerConfigFetcher = issuerConfigFetcher;
527
1007
  this.clientRegistrar = clientRegistrar;
1008
+ this.storageUtility = storageUtility;
1009
+ this.issuerConfigFetcher = issuerConfigFetcher;
1010
+ this.clientRegistrar = clientRegistrar;
528
1011
  }
529
1012
  async refresh(sessionId, refreshToken, dpopKey, eventEmitter) {
530
1013
  const oidcContext = await loadOidcContextFromStorage(sessionId, this.storageUtility, this.issuerConfigFetcher);
1014
+ // This should also retrieve the client from storage
531
1015
  const clientInfo = await this.clientRegistrar.getClient({ sessionId }, oidcContext.issuerConfig);
532
1016
  if (refreshToken === undefined) {
1017
+ // TODO: in a next PR, look up storage for a refresh token
533
1018
  throw new Error(`Session [${sessionId}] has no refresh token to allow it to refresh its access token.`);
534
1019
  }
535
1020
  if (oidcContext.dpop && dpopKey === undefined) {
@@ -546,6 +1031,31 @@ class TokenRefresher {
546
1031
  }
547
1032
  }
548
1033
 
1034
+ //
1035
+ // Copyright Inrupt Inc.
1036
+ //
1037
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1038
+ // of this software and associated documentation files (the "Software"), to deal in
1039
+ // the Software without restriction, including without limitation the rights to use,
1040
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
1041
+ // Software, and to permit persons to whom the Software is furnished to do so,
1042
+ // subject to the following conditions:
1043
+ //
1044
+ // The above copyright notice and this permission notice shall be included in
1045
+ // all copies or substantial portions of the Software.
1046
+ //
1047
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1048
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
1049
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1050
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1051
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1052
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1053
+ //
1054
+ /**
1055
+ *
1056
+ * @param dependencies
1057
+ * @deprecated This function will be removed from the external API in an upcoming release.
1058
+ */
549
1059
  function getClientAuthenticationWithDependencies(dependencies) {
550
1060
  const inMemoryStorage = new InMemoryStorage();
551
1061
  const secureStorage = dependencies.secureStorage || inMemoryStorage;
@@ -556,22 +1066,69 @@ function getClientAuthenticationWithDependencies(dependencies) {
556
1066
  const sessionInfoManager = new SessionInfoManager(storageUtility);
557
1067
  const tokenRefresher = new TokenRefresher(storageUtility, issuerConfigFetcher, clientRegistrar);
558
1068
  const redirector = new Redirector();
1069
+ // make new handler for redirect and login
559
1070
  const loginHandler = new OidcLoginHandler(storageUtility, new AuthorizationCodeWithPkceOidcHandler(storageUtility, redirector), issuerConfigFetcher, clientRegistrar);
560
1071
  const redirectHandler = new AggregateRedirectHandler([
561
1072
  new ErrorOidcHandler(),
562
1073
  new AuthCodeRedirectHandler(storageUtility, sessionInfoManager, issuerConfigFetcher, clientRegistrar, tokenRefresher),
1074
+ // This catch-all class will always be able to handle the
1075
+ // redirect IRI, so it must be registered last.
563
1076
  new FallbackRedirectHandler(),
564
1077
  ]);
565
1078
  return new ClientAuthentication(loginHandler, redirectHandler, new IWaterfallLogoutHandler(sessionInfoManager, redirector), sessionInfoManager, issuerConfigFetcher);
566
1079
  }
567
1080
 
1081
+ //
1082
+ // Copyright Inrupt Inc.
1083
+ //
1084
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1085
+ // of this software and associated documentation files (the "Software"), to deal in
1086
+ // the Software without restriction, including without limitation the rights to use,
1087
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
1088
+ // Software, and to permit persons to whom the Software is furnished to do so,
1089
+ // subject to the following conditions:
1090
+ //
1091
+ // The above copyright notice and this permission notice shall be included in
1092
+ // all copies or substantial portions of the Software.
1093
+ //
1094
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1095
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
1096
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1097
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1098
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1099
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1100
+ //
568
1101
  const KEY_CURRENT_SESSION = `${SOLID_CLIENT_AUTHN_KEY_PREFIX}currentSession`;
569
1102
  const KEY_CURRENT_URL = `${SOLID_CLIENT_AUTHN_KEY_PREFIX}currentUrl`;
570
1103
 
1104
+ //
1105
+ // Copyright Inrupt Inc.
1106
+ //
1107
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1108
+ // of this software and associated documentation files (the "Software"), to deal in
1109
+ // the Software without restriction, including without limitation the rights to use,
1110
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
1111
+ // Software, and to permit persons to whom the Software is furnished to do so,
1112
+ // subject to the following conditions:
1113
+ //
1114
+ // The above copyright notice and this permission notice shall be included in
1115
+ // all copies or substantial portions of the Software.
1116
+ //
1117
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1118
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
1119
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1120
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1121
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1122
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1123
+ //
571
1124
  async function silentlyAuthenticate(sessionId, clientAuthn, session) {
572
1125
  var _a;
573
1126
  const storedSessionInfo = await clientAuthn.validateCurrentSession(sessionId);
574
1127
  if (storedSessionInfo !== null) {
1128
+ // It can be really useful to save the user's current browser location,
1129
+ // so that we can restore it after completing the silent authentication
1130
+ // on incoming redirect. This way, the user is eventually redirected back
1131
+ // to the page they were on and not to the app's redirect page.
575
1132
  window.localStorage.setItem(KEY_CURRENT_URL, window.location.href);
576
1133
  await clientAuthn.login({
577
1134
  sessionId,
@@ -589,21 +1146,68 @@ async function silentlyAuthenticate(sessionId, clientAuthn, session) {
589
1146
  function isLoggedIn(sessionInfo) {
590
1147
  return !!(sessionInfo === null || sessionInfo === void 0 ? void 0 : sessionInfo.isLoggedIn);
591
1148
  }
1149
+ /**
1150
+ * A {@link Session} object represents a user's session on an application. The session holds state, as it stores information enabling acces to private resources after login for instance.
1151
+ */
592
1152
  class Session extends EventEmitter {
1153
+ /**
1154
+ * Session object constructor. Typically called as follows:
1155
+ *
1156
+ * ```typescript
1157
+ * const session = new Session();
1158
+ * ```
1159
+ *
1160
+ * See also [getDefaultSession](https://docs.inrupt.com/developer-tools/api/javascript/solid-client-authn-browser/functions.html#getdefaultsession).
1161
+ *
1162
+ * @param sessionOptions The options enabling the correct instantiation of
1163
+ * the session. Either both storages or clientAuthentication are required. For
1164
+ * more information, see {@link ISessionOptions}.
1165
+ * @param sessionId A string uniquely identifying the session.
1166
+ *
1167
+ */
593
1168
  constructor(sessionOptions = {}, sessionId = undefined) {
594
1169
  super();
595
1170
  this.tokenRequestInProgress = false;
1171
+ /**
1172
+ * Triggers the login process. Note that this method will redirect the user away from your app.
1173
+ *
1174
+ * @param options Parameter to customize the login behaviour. In particular, two options are mandatory: `options.oidcIssuer`, the user's identity provider, and `options.redirectUrl`, the URL to which the user will be redirected after logging in their identity provider.
1175
+ * @returns This method should redirect the user away from the app: it does not return anything. The login process is completed by {@linkcode handleIncomingRedirect}.
1176
+ */
1177
+ // Define these functions as properties so that they don't get accidentally re-bound.
1178
+ // Isn't Javascript fun?
596
1179
  this.login = async (options) => {
597
1180
  var _a;
598
1181
  await this.clientAuthentication.login({
599
1182
  sessionId: this.info.sessionId,
600
1183
  ...options,
1184
+ // Defaults the token type to DPoP
601
1185
  tokenType: (_a = options.tokenType) !== null && _a !== void 0 ? _a : "DPoP",
602
1186
  }, this.events);
1187
+ // `login` redirects the user away from the app,
1188
+ // so unless it throws an error, there is no code that should run afterwards
1189
+ // (since there is no "after" in the lifetime of the script).
1190
+ // Hence, this Promise never resolves:
603
1191
  return new Promise(() => { });
604
1192
  };
1193
+ /**
1194
+ * Fetches data using available login information. If the user is not logged in, this will behave as a regular `fetch`. The signature of this method is identical to the [canonical `fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
1195
+ *
1196
+ * @param url The URL from which data should be fetched.
1197
+ * @param init Optional parameters customizing the request, by specifying an HTTP method, headers, a body, etc. Follows the [WHATWG Fetch Standard](https://fetch.spec.whatwg.org/).
1198
+ */
605
1199
  this.fetch = (url, init) => this.clientAuthentication.fetch(url, init);
1200
+ /**
1201
+ * An internal logout function, to control whether or not the logout signal
1202
+ * should be sent, i.e. if the logout was user-initiated or is the result of
1203
+ * an external event.
1204
+ *
1205
+ * @hidden
1206
+ */
606
1207
  this.internalLogout = async (emitSignal, options) => {
1208
+ // Clearing this value means that silent refresh will no longer be attempted.
1209
+ // In particular, in the case of a silent authentication error it prevents
1210
+ // from getting stuck in an authentication retries loop.
607
1211
  window.localStorage.removeItem(KEY_CURRENT_SESSION);
608
1212
  await this.clientAuthentication.logout(this.info.sessionId, options);
609
1213
  this.info.isLoggedIn = false;
@@ -611,7 +1215,50 @@ class Session extends EventEmitter {
611
1215
  this.events.emit(EVENTS.LOGOUT);
612
1216
  }
613
1217
  };
1218
+ /**
1219
+ * Logs the user out of the application.
1220
+ *
1221
+ * There are 2 types of logout supported by this library,
1222
+ * `app` logout and `idp` logout.
1223
+ *
1224
+ * App logout will log the user out within the application
1225
+ * by clearing any session data from the browser. It does
1226
+ * not log the user out of their Solid identity provider,
1227
+ * and should not redirect the user away.
1228
+ * App logout can be performed as follows:
1229
+ * ```typescript
1230
+ * await session.logout({ logoutType: 'app' });
1231
+ * ```
1232
+ *
1233
+ * IDP logout will log the user out of their Solid identity provider,
1234
+ * and will redirect the user away from the application to do so. In order
1235
+ * for users to be redirected back to `postLogoutUrl` you MUST include the
1236
+ * `postLogoutUrl` value in the `post_logout_redirect_uris` field in the
1237
+ * [Client ID Document](https://docs.inrupt.com/ess/latest/security/authentication/#client-identifier-client-id).
1238
+ * IDP logout can be performed as follows:
1239
+ * ```typescript
1240
+ * await session.logout({
1241
+ * logoutType: 'idp',
1242
+ * // An optional URL to redirect to after logout has completed;
1243
+ * // this MUST match a logout URL listed in the Client ID Document
1244
+ * // of the application that is logged in.
1245
+ * // If the application is logged in with a Client ID that is not
1246
+ * // a URI dereferencing to a Client ID Document then users will
1247
+ * // not be redirected back to the `postLogoutUrl` after logout.
1248
+ * postLogoutUrl: 'https://example.com/logout',
1249
+ * // An optional value to be included in the query parameters
1250
+ * // when the IDP provider redirects the user to the postLogoutRedirectUrl.
1251
+ * state: "my-state"
1252
+ * });
1253
+ * ```
1254
+ */
614
1255
  this.logout = async (options) => this.internalLogout(true, options);
1256
+ /**
1257
+ * Completes the login process by processing the information provided by the
1258
+ * Solid identity provider through redirect.
1259
+ *
1260
+ * @param options See {@see IHandleIncomingRedirectOptions}.
1261
+ */
615
1262
  this.handleIncomingRedirect = async (inputOptions = {}) => {
616
1263
  var _a;
617
1264
  if (this.info.isLoggedIn) {
@@ -628,17 +1275,33 @@ class Session extends EventEmitter {
628
1275
  this.setSessionInfo(sessionInfo);
629
1276
  const currentUrl = window.localStorage.getItem(KEY_CURRENT_URL);
630
1277
  if (currentUrl === null) {
1278
+ // The login event can only be triggered **after** the user has been
1279
+ // redirected from the IdP with access and ID tokens.
631
1280
  this.events.emit(EVENTS.LOGIN);
632
1281
  }
633
1282
  else {
1283
+ // If an URL is stored in local storage, we are being logged in after a
1284
+ // silent authentication, so remove our currently stored URL location
1285
+ // to clean up our state now that we are completing the re-login process.
634
1286
  window.localStorage.removeItem(KEY_CURRENT_URL);
635
1287
  this.events.emit(EVENTS.SESSION_RESTORED, currentUrl);
636
1288
  }
637
1289
  }
638
1290
  else if (options.restorePreviousSession === true) {
1291
+ // Silent authentication happens after a refresh, which means there are no
1292
+ // OAuth params in the current location IRI. It can only succeed if a session
1293
+ // was previously logged in, in which case its ID will be present with a known
1294
+ // identifier in local storage.
1295
+ // Check if we have a locally stored session ID...
639
1296
  const storedSessionId = window.localStorage.getItem(KEY_CURRENT_SESSION);
1297
+ // ...if not, then there is no ID token, and so silent authentication cannot happen, but
1298
+ // if we do have a stored session ID, attempt to re-authenticate now silently.
640
1299
  if (storedSessionId !== null) {
641
1300
  const attemptedSilentAuthentication = await silentlyAuthenticate(storedSessionId, this.clientAuthentication, this);
1301
+ // At this point, we know that the main window will imminently be redirected.
1302
+ // However, this redirect is asynchronous and there is no way to halt execution
1303
+ // until it happens precisely. That's why the current Promise simply does not
1304
+ // resolve.
642
1305
  if (attemptedSilentAuthentication) {
643
1306
  return new Promise(() => { });
644
1307
  }
@@ -647,6 +1310,10 @@ class Session extends EventEmitter {
647
1310
  this.tokenRequestInProgress = false;
648
1311
  return sessionInfo;
649
1312
  };
1313
+ // Until Session no longer implements EventEmitter, this.events is just a proxy
1314
+ // to this (with some interface filtering). When we make the breaking change,
1315
+ // this.events will be a regular EventEmitter (implementing ISessionEventEmitter):
1316
+ // this.events = new EventEmitter();
650
1317
  this.events = new Proxy(this, buildProxyHandler(Session.prototype, "events only implements ISessionEventListener"));
651
1318
  if (sessionOptions.clientAuthentication) {
652
1319
  this.clientAuthentication = sessionOptions.clientAuthentication;
@@ -673,22 +1340,63 @@ class Session extends EventEmitter {
673
1340
  isLoggedIn: false,
674
1341
  };
675
1342
  }
1343
+ // When a session is logged in, we want to track its ID in local storage to
1344
+ // enable silent refresh. The current session ID specifically stored in 'localStorage'
1345
+ // (as opposed to using our storage abstraction layer) because it is only
1346
+ // used in a browser-specific mechanism.
676
1347
  this.events.on(EVENTS.LOGIN, () => window.localStorage.setItem(KEY_CURRENT_SESSION, this.info.sessionId));
677
1348
  this.events.on(EVENTS.SESSION_EXPIRED, () => this.internalLogout(false));
678
1349
  this.events.on(EVENTS.ERROR, () => this.internalLogout(false));
679
1350
  }
1351
+ /**
1352
+ * Register a callback function to be called when a user completes login.
1353
+ *
1354
+ * The callback is called when {@link handleIncomingRedirect} completes successfully.
1355
+ *
1356
+ * @param callback The function called when a user completes login.
1357
+ * @deprecated Prefer session.events.on(EVENTS.LOGIN, callback)
1358
+ */
680
1359
  onLogin(callback) {
681
1360
  this.events.on(EVENTS.LOGIN, callback);
682
1361
  }
1362
+ /**
1363
+ * Register a callback function to be called when a user logs out:
1364
+ *
1365
+ * @param callback The function called when a user completes logout.
1366
+ * @deprecated Prefer session.events.on(EVENTS.LOGOUT, callback)
1367
+ */
683
1368
  onLogout(callback) {
684
1369
  this.events.on(EVENTS.LOGOUT, callback);
685
1370
  }
1371
+ /**
1372
+ * Register a callback function to be called when a user logs out:
1373
+ *
1374
+ * @param callback The function called when an error occurs.
1375
+ * @since 1.11.0
1376
+ * @deprecated Prefer session.events.on(EVENTS.ERROR, callback)
1377
+ */
686
1378
  onError(callback) {
687
1379
  this.events.on(EVENTS.ERROR, callback);
688
1380
  }
1381
+ /**
1382
+ * Register a callback function to be called when a session is restored.
1383
+ *
1384
+ * Note: the callback will be called with the saved value of the 'current URL'
1385
+ * at the time the session was restored.
1386
+ *
1387
+ * @param callback The function called when a user's already logged-in session is restored, e.g., after a silent authentication is completed after a page refresh.
1388
+ * @deprecated Prefer session.events.on(EVENTS.SESSION_RESTORED, callback)
1389
+ */
689
1390
  onSessionRestore(callback) {
690
1391
  this.events.on(EVENTS.SESSION_RESTORED, callback);
691
1392
  }
1393
+ /**
1394
+ * Register a callback that runs when the session expires and can no longer
1395
+ * make authenticated requests, but following a user logout.
1396
+ * @param callback The function that runs on session expiration.
1397
+ * @since 1.11.0
1398
+ * @deprecated Prefer session.events.on(EVENTS.SESSION_EXPIRED, callback)
1399
+ */
692
1400
  onSessionExpiration(callback) {
693
1401
  this.events.on(EVENTS.SESSION_EXPIRED, callback);
694
1402
  }
@@ -703,41 +1411,132 @@ class Session extends EventEmitter {
703
1411
  }
704
1412
  }
705
1413
 
1414
+ //
1415
+ // Copyright Inrupt Inc.
1416
+ //
1417
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1418
+ // of this software and associated documentation files (the "Software"), to deal in
1419
+ // the Software without restriction, including without limitation the rights to use,
1420
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
1421
+ // Software, and to permit persons to whom the Software is furnished to do so,
1422
+ // subject to the following conditions:
1423
+ //
1424
+ // The above copyright notice and this permission notice shall be included in
1425
+ // all copies or substantial portions of the Software.
1426
+ //
1427
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1428
+ // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
1429
+ // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1430
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1431
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1432
+ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1433
+ //
706
1434
  let defaultSession;
1435
+ /**
1436
+ * Obtain the {@link Session} used when not explicitly instantiating one yourself.
1437
+ *
1438
+ * When using the top-level exports {@link fetch}, {@link login}, {@link logout},
1439
+ * {@link handleIncomingRedirect}, {@link onLogin} and {@link onLogout}, these apply to an
1440
+ * implicitly-instantiated {@link Session}.
1441
+ * This function returns a reference to that Session in order to obtain e.g. the current user's
1442
+ * WebID.
1443
+ * @since 1.3.0
1444
+ */
707
1445
  function getDefaultSession() {
708
1446
  if (typeof defaultSession === "undefined") {
709
1447
  defaultSession = new Session();
710
1448
  }
711
1449
  return defaultSession;
712
1450
  }
1451
+ /**
1452
+ * This function's signature is equal to `window.fetch`, but if the current user is authenticated
1453
+ * (see [[login]] and [[handleIncomingRedirect]]), requests made using it will include that user's
1454
+ * credentials. If not, this will behave just like the regular `window.fetch`.
1455
+ *
1456
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch}
1457
+ * @since 1.3.0
1458
+ */
1459
+ /* eslint-disable-next-line no-shadow */
713
1460
  const fetch = (...args) => {
714
1461
  const session = getDefaultSession();
715
1462
  return session.fetch(...args);
716
1463
  };
1464
+ /**
1465
+ * Triggers the login process. Note that this method will redirect the user away from your app.
1466
+ *
1467
+ * @param options Parameter to customize the login behaviour. In particular, two options are mandatory: `options.oidcIssuer`, the user's identity provider, and `options.redirectUrl`, the URL to which the user will be redirected after logging in their identity provider.
1468
+ * @returns This method should redirect the user away from the app: it does not return anything. The login process is completed by [[handleIncomingRedirect]].
1469
+ * @since 1.3.0
1470
+ */
717
1471
  const login = (...args) => {
718
1472
  const session = getDefaultSession();
719
1473
  return session.login(...args);
720
1474
  };
1475
+ /**
1476
+ * Logs the user out of the application.
1477
+ *
1478
+ * By default this does not log the user out of their Solid identity provider.
1479
+ * In order to do so, you must set the logoutType to `idp`. For usage details
1480
+ * see {@link Session.logout}.
1481
+ *
1482
+ * @since 1.3.0
1483
+ */
721
1484
  const logout = (...args) => {
722
1485
  const session = getDefaultSession();
723
1486
  return session.logout(...args);
724
1487
  };
1488
+ /**
1489
+ * Completes the login process by processing the information provided by the Solid identity provider through redirect.
1490
+ *
1491
+ * @param url The URL of the page handling the redirect, including the query parameters — these contain the information to process the login.
1492
+ * @since 1.3.0
1493
+ */
725
1494
  const handleIncomingRedirect = (...args) => {
726
1495
  const session = getDefaultSession();
727
1496
  return session.handleIncomingRedirect(...args);
728
1497
  };
1498
+ /**
1499
+ * Register a callback function to be called when a user completes login.
1500
+ *
1501
+ * The callback is called when {@link handleIncomingRedirect} completes successfully.
1502
+ * @since 1.3.0
1503
+ *
1504
+ * @param callback The function called when a user completes login.
1505
+ * @deprecated Prefer events.on(EVENTS.LOGIN, callback)
1506
+
1507
+ */
729
1508
  const onLogin = (...args) => {
730
1509
  const session = getDefaultSession();
731
1510
  return session.onLogin(...args);
732
1511
  };
1512
+ /**
1513
+ * Register a callback function to be called when a user logs out:
1514
+ *
1515
+ * @param callback The function called when a user completes logout.
1516
+ * @since 1.3.0
1517
+ * @deprecated Prefer events.on(EVENTS.LOGOUT, callback)
1518
+ *
1519
+ */
733
1520
  const onLogout = (...args) => {
734
1521
  const session = getDefaultSession();
735
1522
  return session.onLogout(...args);
736
1523
  };
1524
+ /**
1525
+ * Register a callback function to be called when a session is restored:
1526
+ *
1527
+ * @param callback The function called when a session is restored.
1528
+ * @since 1.3.0
1529
+ * @deprecated Prefer events.on(EVENTS.SESSION_RESTORED, callback)
1530
+ */
737
1531
  const onSessionRestore = (...args) => {
738
1532
  const session = getDefaultSession();
739
1533
  return session.onSessionRestore(...args);
740
1534
  };
1535
+ /**
1536
+ * {@link SessionEventEmitter} instance to subscribe to events by the default session.
1537
+ *
1538
+ * @since 1.14.0
1539
+ */
741
1540
  const events = () => {
742
1541
  return getDefaultSession().events;
743
1542
  };