@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
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
|
|
51
51
|
jest.mock("@inrupt/universal-fetch", () => {
|
|
52
52
|
const fetchModule = jest.requireActual(
|
|
53
|
-
"@inrupt/universal-fetch"
|
|
53
|
+
"@inrupt/universal-fetch",
|
|
54
54
|
) as typeof UniversalFetch;
|
|
55
55
|
return {
|
|
56
56
|
...fetchModule,
|
|
@@ -162,7 +162,7 @@ jest.useFakeTimers();
|
|
|
162
162
|
|
|
163
163
|
function mockOidcClient(): typeof OidcClientExt {
|
|
164
164
|
const mockedOidcClient = jest.requireMock<typeof OidcClientExt>(
|
|
165
|
-
"@inrupt/oidc-client-ext"
|
|
165
|
+
"@inrupt/oidc-client-ext",
|
|
166
166
|
);
|
|
167
167
|
mockedOidcClient.getDpopToken = jest
|
|
168
168
|
.fn<typeof mockedOidcClient.getDpopToken>()
|
|
@@ -196,14 +196,14 @@ function mockClientRegistrar(client: IClient): IClientRegistrar {
|
|
|
196
196
|
return {
|
|
197
197
|
getClient: async (
|
|
198
198
|
_options: IClientRegistrarOptions,
|
|
199
|
-
_issuer: IIssuerConfig
|
|
199
|
+
_issuer: IIssuerConfig,
|
|
200
200
|
): Promise<IClient> => client,
|
|
201
201
|
};
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
const mockFetch = (response: Response) => {
|
|
205
205
|
const { fetch: mockedFetch } = jest.requireMock(
|
|
206
|
-
"@inrupt/universal-fetch"
|
|
206
|
+
"@inrupt/universal-fetch",
|
|
207
207
|
) as jest.Mocked<typeof UniversalFetch>;
|
|
208
208
|
mockedFetch.mockResolvedValueOnce(response);
|
|
209
209
|
return mockedFetch;
|
|
@@ -218,14 +218,14 @@ const defaultMocks = {
|
|
|
218
218
|
};
|
|
219
219
|
|
|
220
220
|
function getAuthCodeRedirectHandler(
|
|
221
|
-
mocks: Partial<typeof defaultMocks> = defaultMocks
|
|
221
|
+
mocks: Partial<typeof defaultMocks> = defaultMocks,
|
|
222
222
|
): AuthCodeRedirectHandler {
|
|
223
223
|
return new AuthCodeRedirectHandler(
|
|
224
224
|
mocks.storageUtility ?? defaultMocks.storageUtility,
|
|
225
225
|
mocks.sessionInfoManager ?? defaultMocks.sessionInfoManager,
|
|
226
226
|
mocks.issuerConfigFetcher ?? defaultMocks.issuerConfigFetcher,
|
|
227
227
|
mocks.clientRegistrar ?? defaultMocks.clientRegistrar,
|
|
228
|
-
mocks.tokenRefresher ?? defaultMocks.tokenRefresher
|
|
228
|
+
mocks.tokenRefresher ?? defaultMocks.tokenRefresher,
|
|
229
229
|
);
|
|
230
230
|
}
|
|
231
231
|
|
|
@@ -246,7 +246,7 @@ const mockDefaultStorageUtility = (
|
|
|
246
246
|
dpop: true,
|
|
247
247
|
codeVerifier: DEFAULT_CODE_VERIFIER,
|
|
248
248
|
redirectUrl: DEFAULT_REDIRECT_URL,
|
|
249
|
-
}
|
|
249
|
+
},
|
|
250
250
|
) =>
|
|
251
251
|
mockStorageUtility({
|
|
252
252
|
[`${USER_SESSION_PREFIX}:${DEFAULT_OAUTH_STATE}`]: {
|
|
@@ -265,16 +265,16 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
265
265
|
it("Accepts a valid url with the correct query", async () => {
|
|
266
266
|
const authCodeRedirectHandler = getAuthCodeRedirectHandler();
|
|
267
267
|
expect(await authCodeRedirectHandler.canHandle(mockRedirectUrl())).toBe(
|
|
268
|
-
true
|
|
268
|
+
true,
|
|
269
269
|
);
|
|
270
270
|
});
|
|
271
271
|
|
|
272
272
|
it("throws on invalid url", async () => {
|
|
273
273
|
const authCodeRedirectHandler = getAuthCodeRedirectHandler();
|
|
274
274
|
await expect(() =>
|
|
275
|
-
authCodeRedirectHandler.canHandle("beep boop I am a robot")
|
|
275
|
+
authCodeRedirectHandler.canHandle("beep boop I am a robot"),
|
|
276
276
|
).rejects.toThrow(
|
|
277
|
-
"[beep boop I am a robot] is not a valid URL, and cannot be used as a redirect URL: TypeError: Invalid URL: beep boop I am a robot"
|
|
277
|
+
"[beep boop I am a robot] is not a valid URL, and cannot be used as a redirect URL: TypeError: Invalid URL: beep boop I am a robot",
|
|
278
278
|
);
|
|
279
279
|
});
|
|
280
280
|
|
|
@@ -282,8 +282,8 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
282
282
|
const authCodeRedirectHandler = getAuthCodeRedirectHandler();
|
|
283
283
|
expect(
|
|
284
284
|
await authCodeRedirectHandler.canHandle(
|
|
285
|
-
"https://coolparty.com/?meep=mop"
|
|
286
|
-
)
|
|
285
|
+
"https://coolparty.com/?meep=mop",
|
|
286
|
+
),
|
|
287
287
|
).toBe(false);
|
|
288
288
|
});
|
|
289
289
|
|
|
@@ -291,8 +291,8 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
291
291
|
const authCodeRedirectHandler = getAuthCodeRedirectHandler();
|
|
292
292
|
expect(
|
|
293
293
|
await authCodeRedirectHandler.canHandle(
|
|
294
|
-
"https://coolparty.com/?state=someState"
|
|
295
|
-
)
|
|
294
|
+
"https://coolparty.com/?state=someState",
|
|
295
|
+
),
|
|
296
296
|
).toBe(false);
|
|
297
297
|
});
|
|
298
298
|
|
|
@@ -300,8 +300,8 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
300
300
|
const authCodeRedirectHandler = getAuthCodeRedirectHandler();
|
|
301
301
|
expect(
|
|
302
302
|
await authCodeRedirectHandler.canHandle(
|
|
303
|
-
"https://coolparty.com/?code=someCode"
|
|
304
|
-
)
|
|
303
|
+
"https://coolparty.com/?code=someCode",
|
|
304
|
+
),
|
|
305
305
|
).toBe(false);
|
|
306
306
|
});
|
|
307
307
|
});
|
|
@@ -310,9 +310,9 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
310
310
|
it("throws on non-redirect URL", async () => {
|
|
311
311
|
const authCodeRedirectHandler = getAuthCodeRedirectHandler();
|
|
312
312
|
await expect(
|
|
313
|
-
authCodeRedirectHandler.handle("https://my.app")
|
|
313
|
+
authCodeRedirectHandler.handle("https://my.app"),
|
|
314
314
|
).rejects.toThrow(
|
|
315
|
-
"AuthCodeRedirectHandler cannot handle [https://my.app]: it is missing one of [code, state]."
|
|
315
|
+
"AuthCodeRedirectHandler cannot handle [https://my.app]: it is missing one of [code, state].",
|
|
316
316
|
);
|
|
317
317
|
});
|
|
318
318
|
|
|
@@ -321,7 +321,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
321
321
|
mockFetch(
|
|
322
322
|
new Response("", {
|
|
323
323
|
status: 200,
|
|
324
|
-
})
|
|
324
|
+
}),
|
|
325
325
|
);
|
|
326
326
|
const storage = mockDefaultStorageUtility();
|
|
327
327
|
|
|
@@ -337,7 +337,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
337
337
|
expect.objectContaining({
|
|
338
338
|
codeVerifier: DEFAULT_CODE_VERIFIER,
|
|
339
339
|
redirectUrl: DEFAULT_REDIRECT_URL,
|
|
340
|
-
})
|
|
340
|
+
}),
|
|
341
341
|
);
|
|
342
342
|
});
|
|
343
343
|
|
|
@@ -346,7 +346,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
346
346
|
mockFetch(
|
|
347
347
|
new Response("", {
|
|
348
348
|
status: 200,
|
|
349
|
-
})
|
|
349
|
+
}),
|
|
350
350
|
);
|
|
351
351
|
const storageUtility = mockDefaultStorageUtility();
|
|
352
352
|
await storageUtility.deleteForUser("mySession", "codeVerifier");
|
|
@@ -355,7 +355,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
355
355
|
});
|
|
356
356
|
|
|
357
357
|
await expect(
|
|
358
|
-
authCodeRedirectHandler.handle(mockRedirectUrl())
|
|
358
|
+
authCodeRedirectHandler.handle(mockRedirectUrl()),
|
|
359
359
|
).rejects.toThrow();
|
|
360
360
|
});
|
|
361
361
|
|
|
@@ -364,7 +364,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
364
364
|
mockFetch(
|
|
365
365
|
new Response("", {
|
|
366
366
|
status: 200,
|
|
367
|
-
})
|
|
367
|
+
}),
|
|
368
368
|
);
|
|
369
369
|
const storageUtility = mockDefaultStorageUtility();
|
|
370
370
|
await storageUtility.deleteForUser("mySession", "redirectUrl");
|
|
@@ -373,7 +373,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
373
373
|
});
|
|
374
374
|
|
|
375
375
|
await expect(
|
|
376
|
-
authCodeRedirectHandler.handle(mockRedirectUrl())
|
|
376
|
+
authCodeRedirectHandler.handle(mockRedirectUrl()),
|
|
377
377
|
).rejects.toThrow();
|
|
378
378
|
});
|
|
379
379
|
|
|
@@ -382,13 +382,13 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
382
382
|
mockFetch(
|
|
383
383
|
new Response("", {
|
|
384
384
|
status: 200,
|
|
385
|
-
})
|
|
385
|
+
}),
|
|
386
386
|
);
|
|
387
387
|
defaultMocks.sessionInfoManager.get.mockResolvedValueOnce(undefined);
|
|
388
388
|
|
|
389
389
|
const authCodeRedirectHandler = getAuthCodeRedirectHandler();
|
|
390
390
|
await expect(
|
|
391
|
-
authCodeRedirectHandler.handle(mockRedirectUrl())
|
|
391
|
+
authCodeRedirectHandler.handle(mockRedirectUrl()),
|
|
392
392
|
).rejects.toThrow("Could not retrieve session");
|
|
393
393
|
});
|
|
394
394
|
|
|
@@ -402,7 +402,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
402
402
|
mockFetch(
|
|
403
403
|
new Response("", {
|
|
404
404
|
status: 200,
|
|
405
|
-
})
|
|
405
|
+
}),
|
|
406
406
|
);
|
|
407
407
|
const storageUtility = mockDefaultStorageUtility();
|
|
408
408
|
const authCodeRedirectHandler = getAuthCodeRedirectHandler({
|
|
@@ -410,7 +410,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
410
410
|
});
|
|
411
411
|
|
|
412
412
|
await expect(
|
|
413
|
-
authCodeRedirectHandler.handle(redirectUrl.href)
|
|
413
|
+
authCodeRedirectHandler.handle(redirectUrl.href),
|
|
414
414
|
).rejects.toThrow();
|
|
415
415
|
});
|
|
416
416
|
|
|
@@ -420,7 +420,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
420
420
|
mockedFetch.mockResolvedValueOnce(
|
|
421
421
|
new Response("", {
|
|
422
422
|
status: 200,
|
|
423
|
-
})
|
|
423
|
+
}),
|
|
424
424
|
);
|
|
425
425
|
|
|
426
426
|
const authCodeRedirectHandler = getAuthCodeRedirectHandler({
|
|
@@ -428,7 +428,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
428
428
|
});
|
|
429
429
|
|
|
430
430
|
const redirectInfo = await authCodeRedirectHandler.handle(
|
|
431
|
-
mockRedirectUrl()
|
|
431
|
+
mockRedirectUrl(),
|
|
432
432
|
);
|
|
433
433
|
|
|
434
434
|
// This will call the oidc-client-ext module, which is mocked at
|
|
@@ -448,14 +448,14 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
448
448
|
mockedFetch.mockResolvedValueOnce(
|
|
449
449
|
new Response("", {
|
|
450
450
|
status: 200,
|
|
451
|
-
})
|
|
451
|
+
}),
|
|
452
452
|
);
|
|
453
453
|
|
|
454
454
|
const authCodeRedirectHandler = getAuthCodeRedirectHandler({
|
|
455
455
|
storageUtility: mockDefaultStorageUtility({ dpop: true }),
|
|
456
456
|
});
|
|
457
457
|
const redirectInfo = await authCodeRedirectHandler.handle(
|
|
458
|
-
mockRedirectUrl()
|
|
458
|
+
mockRedirectUrl(),
|
|
459
459
|
);
|
|
460
460
|
await redirectInfo.fetch("https://some.other.url");
|
|
461
461
|
|
|
@@ -468,7 +468,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
468
468
|
mockFetch(
|
|
469
469
|
new Response("", {
|
|
470
470
|
status: 200,
|
|
471
|
-
})
|
|
471
|
+
}),
|
|
472
472
|
);
|
|
473
473
|
|
|
474
474
|
const mockedStorage = mockDefaultStorageUtility();
|
|
@@ -482,7 +482,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
482
482
|
await expect(
|
|
483
483
|
mockedStorage.getForUser("mySession", "idToken", {
|
|
484
484
|
secure: false,
|
|
485
|
-
})
|
|
485
|
+
}),
|
|
486
486
|
).resolves.toBeUndefined();
|
|
487
487
|
});
|
|
488
488
|
|
|
@@ -492,7 +492,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
492
492
|
mockFetch(
|
|
493
493
|
new Response("", {
|
|
494
494
|
status: 200,
|
|
495
|
-
})
|
|
495
|
+
}),
|
|
496
496
|
);
|
|
497
497
|
|
|
498
498
|
const mockedStorage = mockDefaultStorageUtility();
|
|
@@ -506,7 +506,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
506
506
|
await expect(
|
|
507
507
|
mockedStorage.getForUser("mySession", "redirectUrl", {
|
|
508
508
|
secure: false,
|
|
509
|
-
})
|
|
509
|
+
}),
|
|
510
510
|
// The redirect URL already in storage shouldn't be overriden on redirect.
|
|
511
511
|
).resolves.toBe(DEFAULT_REDIRECT_URL);
|
|
512
512
|
});
|
|
@@ -526,11 +526,11 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
526
526
|
});
|
|
527
527
|
|
|
528
528
|
const sessionInfo = await authCodeRedirectHandler.handle(
|
|
529
|
-
mockRedirectUrl()
|
|
529
|
+
mockRedirectUrl(),
|
|
530
530
|
);
|
|
531
531
|
|
|
532
532
|
expect(sessionInfo.expirationDate).toBe(
|
|
533
|
-
MOCK_TIMESTAMP + MOCK_EXPIRE_TIME * 1000
|
|
533
|
+
MOCK_TIMESTAMP + MOCK_EXPIRE_TIME * 1000,
|
|
534
534
|
);
|
|
535
535
|
});
|
|
536
536
|
|
|
@@ -553,7 +553,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
553
553
|
});
|
|
554
554
|
|
|
555
555
|
const sessionInfo = await authCodeRedirectHandler.handle(
|
|
556
|
-
mockRedirectUrl()
|
|
556
|
+
mockRedirectUrl(),
|
|
557
557
|
);
|
|
558
558
|
|
|
559
559
|
expect(sessionInfo.expirationDate).toBeUndefined();
|
|
@@ -583,11 +583,11 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
583
583
|
}>("@inrupt/solid-client-authn-core");
|
|
584
584
|
const mockAuthenticatedFetchBuild = jest.spyOn(
|
|
585
585
|
coreModule,
|
|
586
|
-
"buildAuthenticatedFetch"
|
|
586
|
+
"buildAuthenticatedFetch",
|
|
587
587
|
);
|
|
588
588
|
|
|
589
589
|
const tokenRefresher = mockTokenRefresher(
|
|
590
|
-
await mockTokenEndpointDpopResponse()
|
|
590
|
+
await mockTokenEndpointDpopResponse(),
|
|
591
591
|
);
|
|
592
592
|
// Run the test
|
|
593
593
|
const authCodeRedirectHandler = getAuthCodeRedirectHandler({
|
|
@@ -607,7 +607,7 @@ describe("AuthCodeRedirectHandler", () => {
|
|
|
607
607
|
tokenRefresher,
|
|
608
608
|
},
|
|
609
609
|
expiresIn: 1337,
|
|
610
|
-
})
|
|
610
|
+
}),
|
|
611
611
|
);
|
|
612
612
|
});
|
|
613
613
|
});
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
// being unauthenticated. This should be looked into when migrating to universal-fetch.
|
|
28
28
|
// import { fetch } from "cross-fetch";
|
|
29
29
|
|
|
30
|
-
import { fetch } from "@inrupt/universal-fetch";
|
|
30
|
+
import { fetch as uniFetch } from "@inrupt/universal-fetch";
|
|
31
31
|
|
|
32
32
|
import type {
|
|
33
33
|
IClient,
|
|
@@ -49,6 +49,9 @@ import type { CodeExchangeResult } from "@inrupt/oidc-client-ext";
|
|
|
49
49
|
import { getDpopToken, getBearerToken } from "@inrupt/oidc-client-ext";
|
|
50
50
|
import type { EventEmitter } from "events";
|
|
51
51
|
|
|
52
|
+
const globalFetch: typeof uniFetch = (...args) =>
|
|
53
|
+
uniFetch.call(globalThis, ...args);
|
|
54
|
+
|
|
52
55
|
/**
|
|
53
56
|
* @hidden
|
|
54
57
|
*/
|
|
@@ -58,8 +61,14 @@ export class AuthCodeRedirectHandler implements IIncomingRedirectHandler {
|
|
|
58
61
|
private sessionInfoManager: ISessionInfoManager,
|
|
59
62
|
private issuerConfigFetcher: IIssuerConfigFetcher,
|
|
60
63
|
private clientRegistrar: IClientRegistrar,
|
|
61
|
-
private tokerRefresher: ITokenRefresher
|
|
62
|
-
) {
|
|
64
|
+
private tokerRefresher: ITokenRefresher,
|
|
65
|
+
) {
|
|
66
|
+
this.storageUtility = storageUtility;
|
|
67
|
+
this.sessionInfoManager = sessionInfoManager;
|
|
68
|
+
this.issuerConfigFetcher = issuerConfigFetcher;
|
|
69
|
+
this.clientRegistrar = clientRegistrar;
|
|
70
|
+
this.tokerRefresher = tokerRefresher;
|
|
71
|
+
}
|
|
63
72
|
|
|
64
73
|
async canHandle(redirectUrl: string): Promise<boolean> {
|
|
65
74
|
try {
|
|
@@ -70,18 +79,18 @@ export class AuthCodeRedirectHandler implements IIncomingRedirectHandler {
|
|
|
70
79
|
);
|
|
71
80
|
} catch (e) {
|
|
72
81
|
throw new Error(
|
|
73
|
-
`[${redirectUrl}] is not a valid URL, and cannot be used as a redirect URL: ${e}
|
|
82
|
+
`[${redirectUrl}] is not a valid URL, and cannot be used as a redirect URL: ${e}`,
|
|
74
83
|
);
|
|
75
84
|
}
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
async handle(
|
|
79
88
|
redirectUrl: string,
|
|
80
|
-
eventEmitter?: EventEmitter
|
|
89
|
+
eventEmitter?: EventEmitter,
|
|
81
90
|
): Promise<IncomingRedirectResult> {
|
|
82
91
|
if (!(await this.canHandle(redirectUrl))) {
|
|
83
92
|
throw new Error(
|
|
84
|
-
`AuthCodeRedirectHandler cannot handle [${redirectUrl}]: it is missing one of [code, state]
|
|
93
|
+
`AuthCodeRedirectHandler cannot handle [${redirectUrl}]: it is missing one of [code, state].`,
|
|
85
94
|
);
|
|
86
95
|
}
|
|
87
96
|
|
|
@@ -93,7 +102,7 @@ export class AuthCodeRedirectHandler implements IIncomingRedirectHandler {
|
|
|
93
102
|
"sessionId",
|
|
94
103
|
{
|
|
95
104
|
errorIfNull: true,
|
|
96
|
-
}
|
|
105
|
+
},
|
|
97
106
|
)) as string;
|
|
98
107
|
|
|
99
108
|
const {
|
|
@@ -104,32 +113,32 @@ export class AuthCodeRedirectHandler implements IIncomingRedirectHandler {
|
|
|
104
113
|
} = await loadOidcContextFromStorage(
|
|
105
114
|
storedSessionId,
|
|
106
115
|
this.storageUtility,
|
|
107
|
-
this.issuerConfigFetcher
|
|
116
|
+
this.issuerConfigFetcher,
|
|
108
117
|
);
|
|
109
118
|
|
|
110
119
|
const iss = url.searchParams.get("iss");
|
|
111
120
|
|
|
112
121
|
if (typeof iss === "string" && iss !== issuerConfig.issuer) {
|
|
113
122
|
throw new Error(
|
|
114
|
-
`The value of the iss parameter (${iss}) does not match the issuer identifier of the authorization server (${issuerConfig.issuer}). See [rfc9207](https://www.rfc-editor.org/rfc/rfc9207.html#section-2.3-3.1.1)
|
|
123
|
+
`The value of the iss parameter (${iss}) does not match the issuer identifier of the authorization server (${issuerConfig.issuer}). See [rfc9207](https://www.rfc-editor.org/rfc/rfc9207.html#section-2.3-3.1.1)`,
|
|
115
124
|
);
|
|
116
125
|
}
|
|
117
126
|
|
|
118
127
|
if (codeVerifier === undefined) {
|
|
119
128
|
throw new Error(
|
|
120
|
-
`The code verifier for session ${storedSessionId} is missing from storage
|
|
129
|
+
`The code verifier for session ${storedSessionId} is missing from storage.`,
|
|
121
130
|
);
|
|
122
131
|
}
|
|
123
132
|
|
|
124
133
|
if (storedRedirectIri === undefined) {
|
|
125
134
|
throw new Error(
|
|
126
|
-
`The redirect URL for session ${storedSessionId} is missing from storage
|
|
135
|
+
`The redirect URL for session ${storedSessionId} is missing from storage.`,
|
|
127
136
|
);
|
|
128
137
|
}
|
|
129
138
|
|
|
130
139
|
const client: IClient = await this.clientRegistrar.getClient(
|
|
131
140
|
{ sessionId: storedSessionId },
|
|
132
|
-
issuerConfig
|
|
141
|
+
issuerConfig,
|
|
133
142
|
);
|
|
134
143
|
|
|
135
144
|
let tokens: CodeExchangeResult;
|
|
@@ -162,12 +171,16 @@ export class AuthCodeRedirectHandler implements IIncomingRedirectHandler {
|
|
|
162
171
|
};
|
|
163
172
|
}
|
|
164
173
|
|
|
165
|
-
const authFetch = await buildAuthenticatedFetch(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
174
|
+
const authFetch = await buildAuthenticatedFetch(
|
|
175
|
+
globalFetch,
|
|
176
|
+
tokens.accessToken,
|
|
177
|
+
{
|
|
178
|
+
dpopKey: tokens.dpopKey,
|
|
179
|
+
refreshOptions,
|
|
180
|
+
eventEmitter,
|
|
181
|
+
expiresIn: tokens.expiresIn,
|
|
182
|
+
},
|
|
183
|
+
);
|
|
171
184
|
|
|
172
185
|
await this.storageUtility.setForUser(
|
|
173
186
|
storedSessionId,
|
|
@@ -175,7 +188,7 @@ export class AuthCodeRedirectHandler implements IIncomingRedirectHandler {
|
|
|
175
188
|
webId: tokens.webId,
|
|
176
189
|
isLoggedIn: "true",
|
|
177
190
|
},
|
|
178
|
-
{ secure: true }
|
|
191
|
+
{ secure: true },
|
|
179
192
|
);
|
|
180
193
|
|
|
181
194
|
const sessionInfo = await this.sessionInfoManager.get(storedSessionId);
|
|
@@ -27,7 +27,7 @@ import { ErrorOidcHandler } from "./ErrorOidcHandler";
|
|
|
27
27
|
|
|
28
28
|
jest.mock("@inrupt/universal-fetch", () => {
|
|
29
29
|
const fetchModule = jest.requireActual(
|
|
30
|
-
"@inrupt/universal-fetch"
|
|
30
|
+
"@inrupt/universal-fetch",
|
|
31
31
|
) as typeof UniversalFetch;
|
|
32
32
|
return {
|
|
33
33
|
...fetchModule,
|
|
@@ -41,14 +41,14 @@ describe("ErrorOidcHandler", () => {
|
|
|
41
41
|
const redirectHandler = new ErrorOidcHandler();
|
|
42
42
|
expect(
|
|
43
43
|
await redirectHandler.canHandle(
|
|
44
|
-
"https://coolparty.com/?code=someCode&state=oauth2_state_value"
|
|
45
|
-
)
|
|
44
|
+
"https://coolparty.com/?code=someCode&state=oauth2_state_value",
|
|
45
|
+
),
|
|
46
46
|
).toBe(false);
|
|
47
47
|
expect(await redirectHandler.canHandle("https://coolparty.com/")).toBe(
|
|
48
|
-
false
|
|
48
|
+
false,
|
|
49
49
|
);
|
|
50
50
|
expect(
|
|
51
|
-
await redirectHandler.canHandle("https://coolparty.com/?test=test")
|
|
51
|
+
await redirectHandler.canHandle("https://coolparty.com/?test=test"),
|
|
52
52
|
).toBe(false);
|
|
53
53
|
});
|
|
54
54
|
|
|
@@ -56,17 +56,17 @@ describe("ErrorOidcHandler", () => {
|
|
|
56
56
|
const redirectHandler = new ErrorOidcHandler();
|
|
57
57
|
expect(
|
|
58
58
|
await redirectHandler.canHandle(
|
|
59
|
-
"https://coolparty.com/?error=some_error"
|
|
60
|
-
)
|
|
59
|
+
"https://coolparty.com/?error=some_error",
|
|
60
|
+
),
|
|
61
61
|
).toBe(true);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
it("throws on invalid url", async () => {
|
|
65
65
|
const redirectHandler = new ErrorOidcHandler();
|
|
66
66
|
await expect(
|
|
67
|
-
redirectHandler.canHandle("beep boop I am a robot")
|
|
67
|
+
redirectHandler.canHandle("beep boop I am a robot"),
|
|
68
68
|
).rejects.toThrow(
|
|
69
|
-
"[beep boop I am a robot] is not a valid URL, and cannot be used as a redirect URL: TypeError: Invalid URL: beep boop I am a robot"
|
|
69
|
+
"[beep boop I am a robot] is not a valid URL, and cannot be used as a redirect URL: TypeError: Invalid URL: beep boop I am a robot",
|
|
70
70
|
);
|
|
71
71
|
});
|
|
72
72
|
});
|
|
@@ -87,14 +87,14 @@ describe("ErrorOidcHandler", () => {
|
|
|
87
87
|
const redirectHandler = new ErrorOidcHandler();
|
|
88
88
|
const mySession = await redirectHandler.handle(
|
|
89
89
|
"https://coolparty.com/?error=error&error_description=unable_to_fetch",
|
|
90
|
-
mockEmitter
|
|
90
|
+
mockEmitter,
|
|
91
91
|
);
|
|
92
92
|
expect(mySession.isLoggedIn).toBe(false);
|
|
93
93
|
expect(mySession.webId).toBeUndefined();
|
|
94
94
|
expect(mockEmit).toHaveBeenCalledWith(
|
|
95
95
|
EVENTS.ERROR,
|
|
96
96
|
"error",
|
|
97
|
-
"unable_to_fetch"
|
|
97
|
+
"unable_to_fetch",
|
|
98
98
|
);
|
|
99
99
|
});
|
|
100
100
|
|
|
@@ -107,7 +107,7 @@ describe("ErrorOidcHandler", () => {
|
|
|
107
107
|
const redirectHandler = new ErrorOidcHandler();
|
|
108
108
|
const mySession = await redirectHandler.handle(
|
|
109
109
|
"https://coolparty.com/?error=error",
|
|
110
|
-
mockEmitter
|
|
110
|
+
mockEmitter,
|
|
111
111
|
);
|
|
112
112
|
expect(mySession.isLoggedIn).toBe(false);
|
|
113
113
|
expect(mySession.webId).toBeUndefined();
|
|
@@ -46,14 +46,14 @@ export class ErrorOidcHandler implements IIncomingRedirectHandler {
|
|
|
46
46
|
return new URL(redirectUrl).searchParams.has("error");
|
|
47
47
|
} catch (e) {
|
|
48
48
|
throw new Error(
|
|
49
|
-
`[${redirectUrl}] is not a valid URL, and cannot be used as a redirect URL: ${e}
|
|
49
|
+
`[${redirectUrl}] is not a valid URL, and cannot be used as a redirect URL: ${e}`,
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
async handle(
|
|
55
55
|
redirectUrl: string,
|
|
56
|
-
eventEmitter?: EventEmitter
|
|
56
|
+
eventEmitter?: EventEmitter,
|
|
57
57
|
): Promise<ISessionInfo & { fetch: typeof fetch }> {
|
|
58
58
|
if (eventEmitter !== undefined) {
|
|
59
59
|
const url = new URL(redirectUrl);
|
|
@@ -25,7 +25,7 @@ import { FallbackRedirectHandler } from "./FallbackRedirectHandler";
|
|
|
25
25
|
|
|
26
26
|
jest.mock("@inrupt/universal-fetch", () => {
|
|
27
27
|
const fetchModule = jest.requireActual(
|
|
28
|
-
"@inrupt/universal-fetch"
|
|
28
|
+
"@inrupt/universal-fetch",
|
|
29
29
|
) as typeof UniversalFetch;
|
|
30
30
|
return {
|
|
31
31
|
...fetchModule,
|
|
@@ -39,23 +39,23 @@ describe("FallbackRedirectHandler", () => {
|
|
|
39
39
|
const redirectHandler = new FallbackRedirectHandler();
|
|
40
40
|
expect(
|
|
41
41
|
await redirectHandler.canHandle(
|
|
42
|
-
"https://coolparty.com/?code=someCode&state=oauth2_state_value"
|
|
43
|
-
)
|
|
42
|
+
"https://coolparty.com/?code=someCode&state=oauth2_state_value",
|
|
43
|
+
),
|
|
44
44
|
).toBe(true);
|
|
45
45
|
expect(await redirectHandler.canHandle("https://coolparty.com/")).toBe(
|
|
46
|
-
true
|
|
46
|
+
true,
|
|
47
47
|
);
|
|
48
48
|
expect(
|
|
49
|
-
await redirectHandler.canHandle("https://coolparty.com/?test=test")
|
|
49
|
+
await redirectHandler.canHandle("https://coolparty.com/?test=test"),
|
|
50
50
|
).toBe(true);
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
it("throws on invalid url", async () => {
|
|
54
54
|
const redirectHandler = new FallbackRedirectHandler();
|
|
55
55
|
await expect(
|
|
56
|
-
redirectHandler.canHandle("beep boop I am a robot")
|
|
56
|
+
redirectHandler.canHandle("beep boop I am a robot"),
|
|
57
57
|
).rejects.toThrow(
|
|
58
|
-
"[beep boop I am a robot] is not a valid URL, and cannot be used as a redirect URL: TypeError: Invalid URL: beep boop I am a robot"
|
|
58
|
+
"[beep boop I am a robot] is not a valid URL, and cannot be used as a redirect URL: TypeError: Invalid URL: beep boop I am a robot",
|
|
59
59
|
);
|
|
60
60
|
});
|
|
61
61
|
});
|
|
@@ -46,14 +46,14 @@ export class FallbackRedirectHandler implements IIncomingRedirectHandler {
|
|
|
46
46
|
return true;
|
|
47
47
|
} catch (e) {
|
|
48
48
|
throw new Error(
|
|
49
|
-
`[${redirectUrl}] is not a valid URL, and cannot be used as a redirect URL: ${e}
|
|
49
|
+
`[${redirectUrl}] is not a valid URL, and cannot be used as a redirect URL: ${e}`,
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
async handle(
|
|
55
55
|
// The argument is ignored, but must be present to implement the interface
|
|
56
|
-
_redirectUrl: string
|
|
56
|
+
_redirectUrl: string,
|
|
57
57
|
): Promise<ISessionInfo & { fetch: typeof fetch }> {
|
|
58
58
|
return getUnauthenticatedSession();
|
|
59
59
|
}
|