@inrupt/solid-client-authn-browser 1.17.0 → 1.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constant.d.ts +2 -2
- package/dist/index.js +53 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +53 -30
- package/dist/index.mjs.map +1 -1
- package/dist/solid-client-authn.bundle.js +7 -7
- package/dist/solid-client-authn.bundle.js.map +1 -1
- package/package.json +6 -6
- package/rollup.config.mjs +1 -1
- package/src/ClientAuthentication.spec.ts +66 -38
- package/src/ClientAuthentication.ts +4 -4
- package/src/Session.spec.ts +44 -44
- package/src/Session.ts +24 -18
- package/src/__mocks__/ClientAuthentication.ts +2 -2
- package/src/defaultSession.ts +4 -3
- package/src/dependencies.ts +5 -5
- package/src/login/oidc/ClientRegistrar.spec.ts +22 -22
- package/src/login/oidc/ClientRegistrar.ts +4 -2
- package/src/login/oidc/IssuerConfigFetcher.spec.ts +25 -25
- package/src/login/oidc/IssuerConfigFetcher.ts +12 -7
- package/src/login/oidc/OidcLoginHandler.spec.ts +15 -15
- package/src/login/oidc/OidcLoginHandler.ts +14 -9
- package/src/login/oidc/Redirector.spec.ts +1 -1
- package/src/login/oidc/__mocks__/ClientRegistrar.ts +3 -3
- package/src/login/oidc/__mocks__/IssuerConfigFetcher.ts +3 -3
- package/src/login/oidc/incomingRedirectHandler/AuthCodeRedirectHandler.spec.ts +42 -42
- package/src/login/oidc/incomingRedirectHandler/AuthCodeRedirectHandler.ts +32 -19
- package/src/login/oidc/incomingRedirectHandler/ErrorOidcHandler.spec.ts +12 -12
- package/src/login/oidc/incomingRedirectHandler/ErrorOidcHandler.ts +2 -2
- package/src/login/oidc/incomingRedirectHandler/FallbackRedirectHandler.spec.ts +7 -7
- package/src/login/oidc/incomingRedirectHandler/FallbackRedirectHandler.ts +2 -2
- package/src/login/oidc/oidcHandlers/AuthorizationCodeWithPkceOidcHandler.spec.ts +17 -17
- package/src/login/oidc/refresh/TokenRefresher.spec.ts +14 -14
- package/src/login/oidc/refresh/TokenRefresher.ts +12 -8
- package/src/login/oidc/refresh/__mocks__/TokenRefresher.ts +1 -1
- package/src/sessionInfo/SessionInfoManager.spec.ts +37 -15
- package/src/sessionInfo/SessionInfoManager.ts +46 -50
- package/src/sessionInfo/__mocks__/SessionInfoManager.ts +3 -3
package/src/Session.spec.ts
CHANGED
|
@@ -40,7 +40,7 @@ import type ClientAuthentication from "./ClientAuthentication";
|
|
|
40
40
|
|
|
41
41
|
jest.mock("@inrupt/universal-fetch", () => {
|
|
42
42
|
const fetchModule = jest.requireActual(
|
|
43
|
-
"@inrupt/universal-fetch"
|
|
43
|
+
"@inrupt/universal-fetch",
|
|
44
44
|
) as typeof UniversalFetch;
|
|
45
45
|
return {
|
|
46
46
|
...fetchModule,
|
|
@@ -164,7 +164,7 @@ describe("Session", () => {
|
|
|
164
164
|
expect.objectContaining({
|
|
165
165
|
tokenType: "Bearer",
|
|
166
166
|
}),
|
|
167
|
-
mySession
|
|
167
|
+
mySession,
|
|
168
168
|
);
|
|
169
169
|
});
|
|
170
170
|
|
|
@@ -248,14 +248,14 @@ describe("Session", () => {
|
|
|
248
248
|
const clientAuthentication = mockClientAuthentication();
|
|
249
249
|
const incomingRedirectHandler = jest.spyOn(
|
|
250
250
|
clientAuthentication,
|
|
251
|
-
"handleIncomingRedirect"
|
|
251
|
+
"handleIncomingRedirect",
|
|
252
252
|
);
|
|
253
253
|
|
|
254
254
|
const mySession = new Session({ clientAuthentication });
|
|
255
255
|
await mySession.handleIncomingRedirect();
|
|
256
256
|
expect(incomingRedirectHandler).toHaveBeenCalledWith(
|
|
257
257
|
"https://some.url",
|
|
258
|
-
mySession
|
|
258
|
+
mySession,
|
|
259
259
|
);
|
|
260
260
|
});
|
|
261
261
|
|
|
@@ -264,7 +264,7 @@ describe("Session", () => {
|
|
|
264
264
|
const clientAuthentication = mockClientAuthentication();
|
|
265
265
|
const incomingRedirectHandler = jest.spyOn(
|
|
266
266
|
clientAuthentication,
|
|
267
|
-
"handleIncomingRedirect"
|
|
267
|
+
"handleIncomingRedirect",
|
|
268
268
|
);
|
|
269
269
|
const mySession = new Session({ clientAuthentication });
|
|
270
270
|
await mySession.handleIncomingRedirect("https://some.url");
|
|
@@ -299,12 +299,12 @@ describe("Session", () => {
|
|
|
299
299
|
sessionId: "a session ID",
|
|
300
300
|
webId: "https://some.webid#them",
|
|
301
301
|
};
|
|
302
|
-
}
|
|
302
|
+
},
|
|
303
303
|
);
|
|
304
304
|
const mySession = new Session({ clientAuthentication });
|
|
305
305
|
await mySession.handleIncomingRedirect("https://some.url");
|
|
306
306
|
expect(window.localStorage.getItem(KEY_CURRENT_SESSION)).toBe(
|
|
307
|
-
mySession.info.sessionId
|
|
307
|
+
mySession.info.sessionId,
|
|
308
308
|
);
|
|
309
309
|
});
|
|
310
310
|
|
|
@@ -317,7 +317,7 @@ describe("Session", () => {
|
|
|
317
317
|
sessionId: "a session ID",
|
|
318
318
|
webId: "https://some.webid#them",
|
|
319
319
|
};
|
|
320
|
-
}
|
|
320
|
+
},
|
|
321
321
|
);
|
|
322
322
|
const mySession = new Session({ clientAuthentication });
|
|
323
323
|
await mySession.handleIncomingRedirect("https://some.url");
|
|
@@ -325,7 +325,7 @@ describe("Session", () => {
|
|
|
325
325
|
await mySession.handleIncomingRedirect("https://some.url");
|
|
326
326
|
// The second request should not hit the wrapped function
|
|
327
327
|
expect(clientAuthentication.handleIncomingRedirect).toHaveBeenCalledTimes(
|
|
328
|
-
1
|
|
328
|
+
1,
|
|
329
329
|
);
|
|
330
330
|
});
|
|
331
331
|
|
|
@@ -336,7 +336,7 @@ describe("Session", () => {
|
|
|
336
336
|
const clientAuthentication = mockClientAuthentication();
|
|
337
337
|
const incomingRedirectHandler = jest.spyOn(
|
|
338
338
|
clientAuthentication,
|
|
339
|
-
"handleIncomingRedirect"
|
|
339
|
+
"handleIncomingRedirect",
|
|
340
340
|
);
|
|
341
341
|
incomingRedirectHandler.mockResolvedValueOnce({
|
|
342
342
|
isLoggedIn: true,
|
|
@@ -348,14 +348,14 @@ describe("Session", () => {
|
|
|
348
348
|
expect(mySession.info.expirationDate).toBe(MOCK_TIMESTAMP + 1337);
|
|
349
349
|
mySession.emit(EVENTS.SESSION_EXTENDED, 1337 * 2);
|
|
350
350
|
expect(mySession.info.expirationDate).toBe(
|
|
351
|
-
MOCK_TIMESTAMP + 1337 * 2 * 1000
|
|
351
|
+
MOCK_TIMESTAMP + 1337 * 2 * 1000,
|
|
352
352
|
);
|
|
353
353
|
});
|
|
354
354
|
|
|
355
355
|
it("leaves the session's info unchanged if no session is obtained after redirect", async () => {
|
|
356
356
|
const clientAuthentication = mockClientAuthentication();
|
|
357
357
|
clientAuthentication.handleIncomingRedirect = jest.fn(
|
|
358
|
-
async (_url: string) => undefined
|
|
358
|
+
async (_url: string) => undefined,
|
|
359
359
|
);
|
|
360
360
|
const mySession = new Session({ clientAuthentication }, "mySession");
|
|
361
361
|
await mySession.handleIncomingRedirect("https://some.url");
|
|
@@ -382,10 +382,10 @@ describe("Session", () => {
|
|
|
382
382
|
clientAuthentication.handleIncomingRedirect = jest.fn(blockingRequest);
|
|
383
383
|
const mySession = new Session({ clientAuthentication });
|
|
384
384
|
const firstTokenRequest = mySession.handleIncomingRedirect(
|
|
385
|
-
"https://my.app/?code=someCode&state=arizona"
|
|
385
|
+
"https://my.app/?code=someCode&state=arizona",
|
|
386
386
|
);
|
|
387
387
|
const secondTokenRequest = mySession.handleIncomingRedirect(
|
|
388
|
-
"https://my.app/?code=someCode&state=arizona"
|
|
388
|
+
"https://my.app/?code=someCode&state=arizona",
|
|
389
389
|
);
|
|
390
390
|
// We know that it has been set by the call to `blockingRequest`.
|
|
391
391
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
@@ -403,14 +403,14 @@ describe("Session", () => {
|
|
|
403
403
|
const clientAuthentication = mockClientAuthentication();
|
|
404
404
|
const incomingRedirectHandler = jest.spyOn(
|
|
405
405
|
clientAuthentication,
|
|
406
|
-
"handleIncomingRedirect"
|
|
406
|
+
"handleIncomingRedirect",
|
|
407
407
|
);
|
|
408
408
|
const mySession = new Session({ clientAuthentication });
|
|
409
409
|
const objectWithHandleIncomingRedirect = {
|
|
410
410
|
handleIncomingRedirect: mySession.handleIncomingRedirect,
|
|
411
411
|
};
|
|
412
412
|
await objectWithHandleIncomingRedirect.handleIncomingRedirect(
|
|
413
|
-
"https://some.url"
|
|
413
|
+
"https://some.url",
|
|
414
414
|
);
|
|
415
415
|
expect(incomingRedirectHandler).toHaveBeenCalled();
|
|
416
416
|
});
|
|
@@ -422,7 +422,7 @@ describe("Session", () => {
|
|
|
422
422
|
mockLocation("https://mock.current/location");
|
|
423
423
|
const mockedStorage = new StorageUtility(
|
|
424
424
|
mockStorage({}),
|
|
425
|
-
mockStorage({})
|
|
425
|
+
mockStorage({}),
|
|
426
426
|
);
|
|
427
427
|
const clientAuthentication = mockClientAuthentication({
|
|
428
428
|
sessionInfoManager: mockSessionInfoManager(mockedStorage),
|
|
@@ -431,7 +431,7 @@ describe("Session", () => {
|
|
|
431
431
|
clientAuthentication.handleIncomingRedirect = jest
|
|
432
432
|
.fn()
|
|
433
433
|
.mockReturnValue(
|
|
434
|
-
incomingRedirectPromise
|
|
434
|
+
incomingRedirectPromise,
|
|
435
435
|
) as typeof clientAuthentication.handleIncomingRedirect;
|
|
436
436
|
const mySession = new Session({ clientAuthentication });
|
|
437
437
|
// eslint-disable-next-line no-void
|
|
@@ -456,7 +456,7 @@ describe("Session", () => {
|
|
|
456
456
|
}),
|
|
457
457
|
// No session information need to be mocked, because `validateCurrentSession`
|
|
458
458
|
// itself is mocked.
|
|
459
|
-
mockStorage({})
|
|
459
|
+
mockStorage({}),
|
|
460
460
|
);
|
|
461
461
|
const clientAuthentication = mockClientAuthentication({
|
|
462
462
|
sessionInfoManager: mockSessionInfoManager(mockedStorage),
|
|
@@ -465,15 +465,15 @@ describe("Session", () => {
|
|
|
465
465
|
clientAuthentication.handleIncomingRedirect = jest
|
|
466
466
|
.fn()
|
|
467
467
|
.mockReturnValueOnce(
|
|
468
|
-
incomingRedirectPromise
|
|
468
|
+
incomingRedirectPromise,
|
|
469
469
|
) as typeof clientAuthentication.handleIncomingRedirect;
|
|
470
470
|
const validateCurrentSessionPromise = Promise.resolve(
|
|
471
|
-
"https://some.issuer/"
|
|
471
|
+
"https://some.issuer/",
|
|
472
472
|
);
|
|
473
473
|
clientAuthentication.validateCurrentSession = jest
|
|
474
474
|
.fn()
|
|
475
475
|
.mockReturnValue(
|
|
476
|
-
validateCurrentSessionPromise
|
|
476
|
+
validateCurrentSessionPromise,
|
|
477
477
|
) as typeof clientAuthentication.validateCurrentSession;
|
|
478
478
|
|
|
479
479
|
const mySession = new Session({ clientAuthentication });
|
|
@@ -485,7 +485,7 @@ describe("Session", () => {
|
|
|
485
485
|
await incomingRedirectPromise;
|
|
486
486
|
await validateCurrentSessionPromise;
|
|
487
487
|
expect(window.localStorage.getItem(KEY_CURRENT_URL)).toBe(
|
|
488
|
-
"https://mock.current/location"
|
|
488
|
+
"https://mock.current/location",
|
|
489
489
|
);
|
|
490
490
|
});
|
|
491
491
|
|
|
@@ -505,7 +505,7 @@ describe("Session", () => {
|
|
|
505
505
|
[`${USER_SESSION_PREFIX}:${sessionId}`]: {
|
|
506
506
|
clientId: "value doesn't matter",
|
|
507
507
|
},
|
|
508
|
-
})
|
|
508
|
+
}),
|
|
509
509
|
);
|
|
510
510
|
const clientAuthentication = mockClientAuthentication({
|
|
511
511
|
sessionInfoManager: mockSessionInfoManager(mockedStorage),
|
|
@@ -513,7 +513,7 @@ describe("Session", () => {
|
|
|
513
513
|
clientAuthentication.handleIncomingRedirect = (
|
|
514
514
|
jest.fn() as any
|
|
515
515
|
).mockResolvedValue(
|
|
516
|
-
undefined
|
|
516
|
+
undefined,
|
|
517
517
|
) as typeof clientAuthentication.handleIncomingRedirect;
|
|
518
518
|
const mySession = new Session({ clientAuthentication });
|
|
519
519
|
// eslint-disable-next-line no-void
|
|
@@ -536,7 +536,7 @@ describe("Session", () => {
|
|
|
536
536
|
isLoggedIn: "true",
|
|
537
537
|
},
|
|
538
538
|
}),
|
|
539
|
-
mockStorage({})
|
|
539
|
+
mockStorage({}),
|
|
540
540
|
);
|
|
541
541
|
const clientAuthentication = mockClientAuthentication({
|
|
542
542
|
sessionInfoManager: mockSessionInfoManager(mockedStorage),
|
|
@@ -551,13 +551,13 @@ describe("Session", () => {
|
|
|
551
551
|
clientAuthentication.validateCurrentSession = jest
|
|
552
552
|
.fn()
|
|
553
553
|
.mockReturnValue(
|
|
554
|
-
validateCurrentSessionPromise
|
|
554
|
+
validateCurrentSessionPromise,
|
|
555
555
|
) as typeof clientAuthentication.validateCurrentSession;
|
|
556
556
|
const incomingRedirectPromise = Promise.resolve();
|
|
557
557
|
clientAuthentication.handleIncomingRedirect = jest
|
|
558
558
|
.fn()
|
|
559
559
|
.mockReturnValueOnce(
|
|
560
|
-
incomingRedirectPromise
|
|
560
|
+
incomingRedirectPromise,
|
|
561
561
|
) as typeof clientAuthentication.handleIncomingRedirect;
|
|
562
562
|
clientAuthentication.login = jest.fn<typeof clientAuthentication.login>();
|
|
563
563
|
|
|
@@ -579,11 +579,11 @@ describe("Session", () => {
|
|
|
579
579
|
clientSecret: "some client secret",
|
|
580
580
|
redirectUrl: "https://some.redirect/url",
|
|
581
581
|
},
|
|
582
|
-
expect.anything()
|
|
582
|
+
expect.anything(),
|
|
583
583
|
);
|
|
584
584
|
// Check that second parameter is of type session
|
|
585
585
|
expect(
|
|
586
|
-
(clientAuthentication.login as any).mock.calls[0][1]
|
|
586
|
+
(clientAuthentication.login as any).mock.calls[0][1],
|
|
587
587
|
).toBeInstanceOf(Session);
|
|
588
588
|
});
|
|
589
589
|
|
|
@@ -599,7 +599,7 @@ describe("Session", () => {
|
|
|
599
599
|
isLoggedIn: "true",
|
|
600
600
|
},
|
|
601
601
|
}),
|
|
602
|
-
mockStorage({})
|
|
602
|
+
mockStorage({}),
|
|
603
603
|
);
|
|
604
604
|
const clientAuthentication = mockClientAuthentication({
|
|
605
605
|
sessionInfoManager: mockSessionInfoManager(mockedStorage),
|
|
@@ -608,13 +608,13 @@ describe("Session", () => {
|
|
|
608
608
|
clientAuthentication.validateCurrentSession = jest
|
|
609
609
|
.fn()
|
|
610
610
|
.mockReturnValue(
|
|
611
|
-
validateCurrentSessionPromise
|
|
611
|
+
validateCurrentSessionPromise,
|
|
612
612
|
) as typeof clientAuthentication.validateCurrentSession;
|
|
613
613
|
const incomingRedirectPromise = Promise.resolve();
|
|
614
614
|
clientAuthentication.handleIncomingRedirect = jest
|
|
615
615
|
.fn()
|
|
616
616
|
.mockReturnValueOnce(
|
|
617
|
-
incomingRedirectPromise
|
|
617
|
+
incomingRedirectPromise,
|
|
618
618
|
) as typeof clientAuthentication.handleIncomingRedirect;
|
|
619
619
|
clientAuthentication.login = jest.fn<typeof clientAuthentication.login>();
|
|
620
620
|
|
|
@@ -640,7 +640,7 @@ describe("Session", () => {
|
|
|
640
640
|
isLoggedIn: "true",
|
|
641
641
|
},
|
|
642
642
|
}),
|
|
643
|
-
mockStorage({})
|
|
643
|
+
mockStorage({}),
|
|
644
644
|
);
|
|
645
645
|
const clientAuthentication = mockClientAuthentication({
|
|
646
646
|
sessionInfoManager: mockSessionInfoManager(mockedStorage),
|
|
@@ -656,7 +656,7 @@ describe("Session", () => {
|
|
|
656
656
|
clientAuthentication.handleIncomingRedirect = (
|
|
657
657
|
jest.fn() as any
|
|
658
658
|
).mockResolvedValue(
|
|
659
|
-
undefined
|
|
659
|
+
undefined,
|
|
660
660
|
) as typeof clientAuthentication.handleIncomingRedirect;
|
|
661
661
|
clientAuthentication.login = jest.fn<typeof clientAuthentication.login>();
|
|
662
662
|
|
|
@@ -679,7 +679,7 @@ describe("Session", () => {
|
|
|
679
679
|
isLoggedIn: "true",
|
|
680
680
|
},
|
|
681
681
|
}),
|
|
682
|
-
mockStorage({})
|
|
682
|
+
mockStorage({}),
|
|
683
683
|
);
|
|
684
684
|
const clientAuthentication = mockClientAuthentication({
|
|
685
685
|
sessionInfoManager: mockSessionInfoManager(mockedStorage),
|
|
@@ -720,7 +720,7 @@ describe("Session", () => {
|
|
|
720
720
|
isLoggedIn: "true",
|
|
721
721
|
},
|
|
722
722
|
}),
|
|
723
|
-
mockStorage({})
|
|
723
|
+
mockStorage({}),
|
|
724
724
|
);
|
|
725
725
|
const clientAuthentication = mockClientAuthentication({
|
|
726
726
|
sessionInfoManager: mockSessionInfoManager(mockedStorage),
|
|
@@ -759,7 +759,7 @@ describe("Session", () => {
|
|
|
759
759
|
isLoggedIn: "true",
|
|
760
760
|
},
|
|
761
761
|
}),
|
|
762
|
-
mockStorage({})
|
|
762
|
+
mockStorage({}),
|
|
763
763
|
);
|
|
764
764
|
const clientAuthentication = mockClientAuthentication({
|
|
765
765
|
sessionInfoManager: mockSessionInfoManager(mockedStorage),
|
|
@@ -781,7 +781,7 @@ describe("Session", () => {
|
|
|
781
781
|
mySession.emit(EVENTS.ERROR, "error", "error_description");
|
|
782
782
|
expect(onErrorCallback).toHaveBeenCalledWith(
|
|
783
783
|
"error",
|
|
784
|
-
"error_description"
|
|
784
|
+
"error_description",
|
|
785
785
|
);
|
|
786
786
|
});
|
|
787
787
|
});
|
|
@@ -807,7 +807,7 @@ describe("Session", () => {
|
|
|
807
807
|
it("does not call the registered callback if login isn't successful", async () => {
|
|
808
808
|
const failCallback = (): void => {
|
|
809
809
|
throw new Error(
|
|
810
|
-
"Should *NOT* call callback - this means test has failed!"
|
|
810
|
+
"Should *NOT* call callback - this means test has failed!",
|
|
811
811
|
);
|
|
812
812
|
};
|
|
813
813
|
const clientAuthentication = mockClientAuthentication();
|
|
@@ -818,12 +818,12 @@ describe("Session", () => {
|
|
|
818
818
|
sessionId: "a session ID",
|
|
819
819
|
webId: "https://some.webid#them",
|
|
820
820
|
};
|
|
821
|
-
}
|
|
821
|
+
},
|
|
822
822
|
);
|
|
823
823
|
const mySession = new Session({ clientAuthentication });
|
|
824
824
|
mySession.onLogin(failCallback);
|
|
825
825
|
await expect(
|
|
826
|
-
mySession.handleIncomingRedirect("https://some.url")
|
|
826
|
+
mySession.handleIncomingRedirect("https://some.url"),
|
|
827
827
|
).resolves.not.toThrow();
|
|
828
828
|
});
|
|
829
829
|
|
|
@@ -836,7 +836,7 @@ describe("Session", () => {
|
|
|
836
836
|
sessionId: "a session ID",
|
|
837
837
|
webId: "https://some.webid#them",
|
|
838
838
|
};
|
|
839
|
-
}
|
|
839
|
+
},
|
|
840
840
|
);
|
|
841
841
|
const mySession = new Session({ clientAuthentication });
|
|
842
842
|
const myCallback = jest.fn((): void => {
|
|
@@ -1035,7 +1035,7 @@ describe("Session", () => {
|
|
|
1035
1035
|
const mySession = new Session();
|
|
1036
1036
|
// @ts-expect-error onLogin is a function on Session, and not SessionEventEmitter
|
|
1037
1037
|
expect(() => mySession.events.onLogin(jest.fn())).toThrow(
|
|
1038
|
-
"[onLogin] is not supported"
|
|
1038
|
+
"[onLogin] is not supported",
|
|
1039
1039
|
);
|
|
1040
1040
|
});
|
|
1041
1041
|
});
|
package/src/Session.ts
CHANGED
|
@@ -101,7 +101,7 @@ export interface IHandleIncomingRedirectOptions {
|
|
|
101
101
|
export async function silentlyAuthenticate(
|
|
102
102
|
sessionId: string,
|
|
103
103
|
clientAuthn: ClientAuthentication,
|
|
104
|
-
session: Session
|
|
104
|
+
session: Session,
|
|
105
105
|
): Promise<boolean> {
|
|
106
106
|
const storedSessionInfo = await clientAuthn.validateCurrentSession(sessionId);
|
|
107
107
|
if (storedSessionInfo !== null) {
|
|
@@ -120,7 +120,7 @@ export async function silentlyAuthenticate(
|
|
|
120
120
|
clientSecret: storedSessionInfo.clientAppSecret,
|
|
121
121
|
tokenType: storedSessionInfo.tokenType ?? "DPoP",
|
|
122
122
|
},
|
|
123
|
-
session.events
|
|
123
|
+
session.events,
|
|
124
124
|
);
|
|
125
125
|
return true;
|
|
126
126
|
}
|
|
@@ -128,7 +128,7 @@ export async function silentlyAuthenticate(
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
function isLoggedIn(
|
|
131
|
-
sessionInfo?: ISessionInfo
|
|
131
|
+
sessionInfo?: ISessionInfo,
|
|
132
132
|
): sessionInfo is ISessionInfo & { isLoggedIn: true } {
|
|
133
133
|
return !!sessionInfo?.isLoggedIn;
|
|
134
134
|
}
|
|
@@ -170,7 +170,7 @@ export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
|
170
170
|
*/
|
|
171
171
|
constructor(
|
|
172
172
|
sessionOptions: Partial<ISessionOptions> = {},
|
|
173
|
-
sessionId: string | undefined = undefined
|
|
173
|
+
sessionId: string | undefined = undefined,
|
|
174
174
|
) {
|
|
175
175
|
super();
|
|
176
176
|
// Until Session no longer implements EventEmitter, this.events is just a proxy
|
|
@@ -181,8 +181,8 @@ export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
|
181
181
|
this,
|
|
182
182
|
buildProxyHandler(
|
|
183
183
|
Session.prototype,
|
|
184
|
-
"events only implements ISessionEventListener"
|
|
185
|
-
)
|
|
184
|
+
"events only implements ISessionEventListener",
|
|
185
|
+
),
|
|
186
186
|
);
|
|
187
187
|
if (sessionOptions.clientAuthentication) {
|
|
188
188
|
this.clientAuthentication = sessionOptions.clientAuthentication;
|
|
@@ -213,7 +213,7 @@ export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
|
213
213
|
// (as opposed to using our storage abstraction layer) because it is only
|
|
214
214
|
// used in a browser-specific mechanism.
|
|
215
215
|
this.events.on(EVENTS.LOGIN, () =>
|
|
216
|
-
window.localStorage.setItem(KEY_CURRENT_SESSION, this.info.sessionId)
|
|
216
|
+
window.localStorage.setItem(KEY_CURRENT_SESSION, this.info.sessionId),
|
|
217
217
|
);
|
|
218
218
|
|
|
219
219
|
this.events.on(EVENTS.SESSION_EXPIRED, () => this.internalLogout(false));
|
|
@@ -237,7 +237,7 @@ export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
|
237
237
|
// Defaults the token type to DPoP
|
|
238
238
|
tokenType: options.tokenType ?? "DPoP",
|
|
239
239
|
},
|
|
240
|
-
this.events
|
|
240
|
+
this.events,
|
|
241
241
|
);
|
|
242
242
|
// `login` redirects the user away from the app,
|
|
243
243
|
// so unless it throws an error, there is no code that should run afterwards
|
|
@@ -264,7 +264,7 @@ export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
|
264
264
|
*/
|
|
265
265
|
private internalLogout = async (
|
|
266
266
|
emitSignal: boolean,
|
|
267
|
-
options?: ILogoutOptions
|
|
267
|
+
options?: ILogoutOptions,
|
|
268
268
|
): Promise<void> => {
|
|
269
269
|
// Clearing this value means that silent refresh will no longer be attempted.
|
|
270
270
|
// In particular, in the case of a silent authentication error it prevents
|
|
@@ -293,14 +293,20 @@ export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
|
293
293
|
* ```
|
|
294
294
|
*
|
|
295
295
|
* IDP logout will log the user out of their Solid identity provider,
|
|
296
|
-
* and will redirect the user away from the application to do so.
|
|
296
|
+
* and will redirect the user away from the application to do so. In order
|
|
297
|
+
* for users to be redirected back to `postLogoutUrl` you MUST include the
|
|
298
|
+
* `postLogoutUrl` value in the `post_logout_redirect_uris` field in the
|
|
299
|
+
* [Client ID Document](https://docs.inrupt.com/ess/latest/security/authentication/#client-identifier-client-id).
|
|
297
300
|
* IDP logout can be performed as follows:
|
|
298
301
|
* ```typescript
|
|
299
302
|
* await session.logout({
|
|
300
303
|
* logoutType: 'idp',
|
|
301
304
|
* // An optional URL to redirect to after logout has completed;
|
|
302
|
-
* // this MUST match a logout URL listed in the
|
|
303
|
-
* // the application that is logged in.
|
|
305
|
+
* // this MUST match a logout URL listed in the Client ID Document
|
|
306
|
+
* // of the application that is logged in.
|
|
307
|
+
* // If the application is logged in with a Client ID that is not
|
|
308
|
+
* // a URI dereferencing to a Client ID Document then users will
|
|
309
|
+
* // not be redirected back to the `postLogoutUrl` after logout.
|
|
304
310
|
* postLogoutUrl: 'https://example.com/logout',
|
|
305
311
|
* // An optional value to be included in the query parameters
|
|
306
312
|
* // when the IDP provider redirects the user to the postLogoutRedirectUrl.
|
|
@@ -318,7 +324,7 @@ export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
|
318
324
|
* @param options See {@see IHandleIncomingRedirectOptions}.
|
|
319
325
|
*/
|
|
320
326
|
handleIncomingRedirect = async (
|
|
321
|
-
inputOptions: string | IHandleIncomingRedirectOptions = {}
|
|
327
|
+
inputOptions: string | IHandleIncomingRedirectOptions = {},
|
|
322
328
|
): Promise<ISessionInfo | undefined> => {
|
|
323
329
|
if (this.info.isLoggedIn) {
|
|
324
330
|
return this.info;
|
|
@@ -334,7 +340,7 @@ export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
|
334
340
|
this.tokenRequestInProgress = true;
|
|
335
341
|
const sessionInfo = await this.clientAuthentication.handleIncomingRedirect(
|
|
336
342
|
url,
|
|
337
|
-
this.events
|
|
343
|
+
this.events,
|
|
338
344
|
);
|
|
339
345
|
if (isLoggedIn(sessionInfo)) {
|
|
340
346
|
this.setSessionInfo(sessionInfo);
|
|
@@ -363,7 +369,7 @@ export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
|
363
369
|
const attemptedSilentAuthentication = await silentlyAuthenticate(
|
|
364
370
|
storedSessionId,
|
|
365
371
|
this.clientAuthentication,
|
|
366
|
-
this
|
|
372
|
+
this,
|
|
367
373
|
);
|
|
368
374
|
// At this point, we know that the main window will imminently be redirected.
|
|
369
375
|
// However, this redirect is asynchronous and there is no way to halt execution
|
|
@@ -410,8 +416,8 @@ export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
|
410
416
|
onError(
|
|
411
417
|
callback: (
|
|
412
418
|
error: string | null,
|
|
413
|
-
errorDescription?: string | null
|
|
414
|
-
) => unknown
|
|
419
|
+
errorDescription?: string | null,
|
|
420
|
+
) => unknown,
|
|
415
421
|
): void {
|
|
416
422
|
this.events.on(EVENTS.ERROR, callback);
|
|
417
423
|
}
|
|
@@ -441,7 +447,7 @@ export class Session extends EventEmitter implements IHasSessionEventListener {
|
|
|
441
447
|
}
|
|
442
448
|
|
|
443
449
|
private setSessionInfo(
|
|
444
|
-
sessionInfo: ISessionInfo & { isLoggedIn: true }
|
|
450
|
+
sessionInfo: ISessionInfo & { isLoggedIn: true },
|
|
445
451
|
): void {
|
|
446
452
|
this.info.isLoggedIn = sessionInfo.isLoggedIn;
|
|
447
453
|
this.info.webId = sessionInfo.webId;
|
|
@@ -48,7 +48,7 @@ type ClientAuthnDependencies = {
|
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
export const mockClientAuthentication = (
|
|
51
|
-
mocks?: Partial<ClientAuthnDependencies
|
|
51
|
+
mocks?: Partial<ClientAuthnDependencies>,
|
|
52
52
|
): ClientAuthentication => {
|
|
53
53
|
const storage = mocks?.storage ?? mockStorageUtility({});
|
|
54
54
|
return new ClientAuthentication(
|
|
@@ -56,6 +56,6 @@ export const mockClientAuthentication = (
|
|
|
56
56
|
mocks?.redirectHandler ?? mockIncomingRedirectHandler(),
|
|
57
57
|
mocks?.logoutHandler ?? mockLogoutHandler(storage),
|
|
58
58
|
mocks?.sessionInfoManager ?? mockSessionInfoManager(storage),
|
|
59
|
-
mocks?.issuerConfigFetcher ?? IssuerConfigFetcherMock
|
|
59
|
+
mocks?.issuerConfigFetcher ?? IssuerConfigFetcherMock,
|
|
60
60
|
);
|
|
61
61
|
};
|
package/src/defaultSession.ts
CHANGED
|
@@ -70,7 +70,8 @@ export const login: Session["login"] = (...args) => {
|
|
|
70
70
|
* Logs the user out of the application.
|
|
71
71
|
*
|
|
72
72
|
* By default this does not log the user out of their Solid identity provider.
|
|
73
|
-
* In order to do so, you must set the logoutType to `idp`.
|
|
73
|
+
* In order to do so, you must set the logoutType to `idp`. For usage details
|
|
74
|
+
* see {@link Session.logout}.
|
|
74
75
|
*
|
|
75
76
|
* @since 1.3.0
|
|
76
77
|
*/
|
|
@@ -113,7 +114,7 @@ export const onLogin: Session["onLogin"] = (...args) => {
|
|
|
113
114
|
* @param callback The function called when a user completes logout.
|
|
114
115
|
* @since 1.3.0
|
|
115
116
|
* @deprecated Prefer events.on(EVENTS.LOGOUT, callback)
|
|
116
|
-
|
|
117
|
+
*
|
|
117
118
|
*/
|
|
118
119
|
export const onLogout: Session["onLogout"] = (...args) => {
|
|
119
120
|
const session = getDefaultSession();
|
|
@@ -135,7 +136,7 @@ export const onSessionRestore: Session["onSessionRestore"] = (...args) => {
|
|
|
135
136
|
/**
|
|
136
137
|
* {@link SessionEventEmitter} instance to subscribe to events by the default session.
|
|
137
138
|
*
|
|
138
|
-
* @since
|
|
139
|
+
* @since 1.14.0
|
|
139
140
|
*/
|
|
140
141
|
export const events = (): Session["events"] => {
|
|
141
142
|
return getDefaultSession().events;
|
package/src/dependencies.ts
CHANGED
|
@@ -62,7 +62,7 @@ export function getClientAuthenticationWithDependencies(dependencies: {
|
|
|
62
62
|
|
|
63
63
|
const storageUtility = new StorageUtilityBrowser(
|
|
64
64
|
secureStorage,
|
|
65
|
-
insecureStorage
|
|
65
|
+
insecureStorage,
|
|
66
66
|
);
|
|
67
67
|
|
|
68
68
|
const issuerConfigFetcher = new IssuerConfigFetcher(storageUtility);
|
|
@@ -73,7 +73,7 @@ export function getClientAuthenticationWithDependencies(dependencies: {
|
|
|
73
73
|
const tokenRefresher = new TokenRefresher(
|
|
74
74
|
storageUtility,
|
|
75
75
|
issuerConfigFetcher,
|
|
76
|
-
clientRegistrar
|
|
76
|
+
clientRegistrar,
|
|
77
77
|
);
|
|
78
78
|
|
|
79
79
|
const redirector = new Redirector();
|
|
@@ -83,7 +83,7 @@ export function getClientAuthenticationWithDependencies(dependencies: {
|
|
|
83
83
|
storageUtility,
|
|
84
84
|
new AuthorizationCodeWithPkceOidcHandler(storageUtility, redirector),
|
|
85
85
|
issuerConfigFetcher,
|
|
86
|
-
clientRegistrar
|
|
86
|
+
clientRegistrar,
|
|
87
87
|
);
|
|
88
88
|
|
|
89
89
|
const redirectHandler = new AggregateRedirectHandler([
|
|
@@ -93,7 +93,7 @@ export function getClientAuthenticationWithDependencies(dependencies: {
|
|
|
93
93
|
sessionInfoManager,
|
|
94
94
|
issuerConfigFetcher,
|
|
95
95
|
clientRegistrar,
|
|
96
|
-
tokenRefresher
|
|
96
|
+
tokenRefresher,
|
|
97
97
|
),
|
|
98
98
|
// This catch-all class will always be able to handle the
|
|
99
99
|
// redirect IRI, so it must be registered last.
|
|
@@ -105,6 +105,6 @@ export function getClientAuthenticationWithDependencies(dependencies: {
|
|
|
105
105
|
redirectHandler,
|
|
106
106
|
new IWaterfallLogoutHandler(sessionInfoManager, redirector),
|
|
107
107
|
sessionInfoManager,
|
|
108
|
-
issuerConfigFetcher
|
|
108
|
+
issuerConfigFetcher,
|
|
109
109
|
);
|
|
110
110
|
}
|