docpouch-client 1.0.3 → 1.0.5
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/.gravatarKey +1 -0
- package/README.md +630 -630
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +131 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +1302 -0
- package/dist/index.d.ts +56 -1
- package/dist/index.js +159 -4
- package/package.json +4 -4
- package/chat-09e440bd-c52c-44b9-bba4-01cebc84bd7b.txt +0 -223
- package/hff +0 -114
- package/jest.config.cjs +0 -18
- package/src/index.ts +0 -1046
- package/tests/docPouchClient.test.ts +0 -654
- package/tests/mock-server.ts +0 -613
- package/tsconfig.build.json +0 -7
- package/tsconfig.json +0 -27
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Socket } from "socket.io-client";
|
|
2
2
|
/**
|
|
3
3
|
* Client for interacting with docPouch API.
|
|
4
|
+
* Supports JWT and OIDC authentication with comprehensive logout capabilities.
|
|
5
|
+
* Provides event emitter functionality for logout events.
|
|
4
6
|
*/
|
|
5
7
|
export default class docPouchClient {
|
|
6
8
|
/**
|
|
@@ -49,6 +51,10 @@ export default class docPouchClient {
|
|
|
49
51
|
* @type {boolean}
|
|
50
52
|
*/
|
|
51
53
|
private connectionInProgress;
|
|
54
|
+
/**
|
|
55
|
+
* Event emitter for logout events
|
|
56
|
+
*/
|
|
57
|
+
private events;
|
|
52
58
|
/**
|
|
53
59
|
* Creates an instance of docPouchClient.
|
|
54
60
|
*
|
|
@@ -227,9 +233,40 @@ export default class docPouchClient {
|
|
|
227
233
|
/**
|
|
228
234
|
* Logs out the client, clearing all tokens and disconnecting WebSocket.
|
|
229
235
|
*
|
|
236
|
+
* @param {LogoutOptions} [options] - Logout options for OIDC logout
|
|
230
237
|
* @returns {Promise<void>}
|
|
231
238
|
*/
|
|
232
|
-
logout(): Promise<void>;
|
|
239
|
+
logout(options?: LogoutOptions): Promise<void>;
|
|
240
|
+
/**
|
|
241
|
+
* Explicitly logout from OIDC provider
|
|
242
|
+
* Redirects to /end_session endpoint
|
|
243
|
+
*
|
|
244
|
+
* @param {LogoutOptions} [options] - Logout options
|
|
245
|
+
* @returns {Promise<void>}
|
|
246
|
+
*/
|
|
247
|
+
logoutOidc(options?: LogoutOptions): Promise<void>;
|
|
248
|
+
/**
|
|
249
|
+
* Logout from JWT (client-side only)
|
|
250
|
+
*
|
|
251
|
+
* @returns {Promise<void>}
|
|
252
|
+
*/
|
|
253
|
+
logoutJwt(): Promise<void>;
|
|
254
|
+
/**
|
|
255
|
+
* Listen for logout events
|
|
256
|
+
*/
|
|
257
|
+
onLogout(callback: () => void): void;
|
|
258
|
+
/**
|
|
259
|
+
* Listen for OIDC logout specifically
|
|
260
|
+
*/
|
|
261
|
+
onOidcLogout(callback: () => void): void;
|
|
262
|
+
/**
|
|
263
|
+
* Listen for JWT logout specifically
|
|
264
|
+
*/
|
|
265
|
+
onJwtLogout(callback: () => void): void;
|
|
266
|
+
/**
|
|
267
|
+
* Emit an event
|
|
268
|
+
*/
|
|
269
|
+
private emit;
|
|
233
270
|
/**
|
|
234
271
|
* Registers a new OIDC client with the server (dynamic client registration).
|
|
235
272
|
*
|
|
@@ -296,6 +333,19 @@ export default class docPouchClient {
|
|
|
296
333
|
private generateCodeVerifier;
|
|
297
334
|
private generateCodeChallenge;
|
|
298
335
|
private generateState;
|
|
336
|
+
/**
|
|
337
|
+
* Check if user was just logged out (after redirect from /end_session)
|
|
338
|
+
* Checks URL for logout indicator or checks localStorage
|
|
339
|
+
*
|
|
340
|
+
* @returns {boolean} True if user was just logged out
|
|
341
|
+
*/
|
|
342
|
+
wasJustLoggedOut(): boolean;
|
|
343
|
+
/**
|
|
344
|
+
* Get post_logout_redirect_uri after OIDC logout
|
|
345
|
+
*
|
|
346
|
+
* @returns {string | null} The post logout redirect URI or null if not set
|
|
347
|
+
*/
|
|
348
|
+
getPostLogoutRedirectUri(): string | null;
|
|
299
349
|
}
|
|
300
350
|
export interface I_UserEntry extends I_UserCreation {
|
|
301
351
|
_id: string;
|
|
@@ -335,6 +385,10 @@ export interface I_LoginResponse {
|
|
|
335
385
|
userName: string;
|
|
336
386
|
expiresIn?: number;
|
|
337
387
|
}
|
|
388
|
+
export interface LogoutOptions {
|
|
389
|
+
redirectUri?: string;
|
|
390
|
+
idTokenHint?: string;
|
|
391
|
+
}
|
|
338
392
|
export interface I_OidcConfig {
|
|
339
393
|
issuer: string;
|
|
340
394
|
clientId: string;
|
|
@@ -342,6 +396,7 @@ export interface I_OidcConfig {
|
|
|
342
396
|
scope?: string;
|
|
343
397
|
scopes?: string[];
|
|
344
398
|
clientSecret?: string;
|
|
399
|
+
postLogoutRedirectUri?: string;
|
|
345
400
|
}
|
|
346
401
|
export interface I_OidcTokenResponse {
|
|
347
402
|
accessToken: string;
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,8 @@ import { io } from "socket.io-client";
|
|
|
2
2
|
import packetJson from '../package.json';
|
|
3
3
|
/**
|
|
4
4
|
* Client for interacting with docPouch API.
|
|
5
|
+
* Supports JWT and OIDC authentication with comprehensive logout capabilities.
|
|
6
|
+
* Provides event emitter functionality for logout events.
|
|
5
7
|
*/
|
|
6
8
|
export default class docPouchClient {
|
|
7
9
|
/**
|
|
@@ -40,6 +42,10 @@ export default class docPouchClient {
|
|
|
40
42
|
* @type {boolean}
|
|
41
43
|
*/
|
|
42
44
|
this.connectionInProgress = false;
|
|
45
|
+
/**
|
|
46
|
+
* Event emitter for logout events
|
|
47
|
+
*/
|
|
48
|
+
this.events = {};
|
|
43
49
|
this.baseUrl = host;
|
|
44
50
|
const socketUrl = host.includes('://') ? host : `https://${host}`;
|
|
45
51
|
const socketUrlWithPort = socketUrl.includes(':') && !socketUrl.endsWith(':')
|
|
@@ -411,11 +417,15 @@ export default class docPouchClient {
|
|
|
411
417
|
return true;
|
|
412
418
|
}
|
|
413
419
|
restoreOidcSession() {
|
|
414
|
-
if (typeof window === 'undefined' || !window.localStorage)
|
|
415
|
-
return false;
|
|
416
420
|
const stored = localStorage.getItem('docpouch_oidc_session');
|
|
417
|
-
if (!stored)
|
|
421
|
+
if (!stored) {
|
|
422
|
+
// If no session, check if user was just logged out
|
|
423
|
+
if (this.wasJustLoggedOut()) {
|
|
424
|
+
// User was logged out, emit oidc-logout event
|
|
425
|
+
this.emit('oidc-logout');
|
|
426
|
+
}
|
|
418
427
|
return false;
|
|
428
|
+
}
|
|
419
429
|
try {
|
|
420
430
|
const session = JSON.parse(stored);
|
|
421
431
|
if (!session.accessToken || Date.now() >= session.expiry) {
|
|
@@ -474,18 +484,134 @@ export default class docPouchClient {
|
|
|
474
484
|
/**
|
|
475
485
|
* Logs out the client, clearing all tokens and disconnecting WebSocket.
|
|
476
486
|
*
|
|
487
|
+
* @param {LogoutOptions} [options] - Logout options for OIDC logout
|
|
488
|
+
* @returns {Promise<void>}
|
|
489
|
+
*/
|
|
490
|
+
async logout(options) {
|
|
491
|
+
const wasOidc = this.authMethod === 'oidc';
|
|
492
|
+
// For OIDC, redirect to /end_session endpoint
|
|
493
|
+
if (wasOidc && this.oidcConfig && typeof window !== 'undefined') {
|
|
494
|
+
const redirectUri = options?.redirectUri || this.oidcConfig.redirectUri || window.location.origin;
|
|
495
|
+
let url = `${this.oidcConfig.issuer}/end_session?post_logout_redirect_uri=${encodeURIComponent(redirectUri)}`;
|
|
496
|
+
// Add id_token_hint if available
|
|
497
|
+
const idToken = options?.idTokenHint || this.oidcIdToken;
|
|
498
|
+
if (idToken) {
|
|
499
|
+
url += `&id_token_hint=${idToken}`;
|
|
500
|
+
}
|
|
501
|
+
// Clear tokens before redirect
|
|
502
|
+
this.authToken = null;
|
|
503
|
+
this.clearOidcTokens();
|
|
504
|
+
this.authMethod = 'none';
|
|
505
|
+
if (this.socket.connected)
|
|
506
|
+
this.socket.disconnect();
|
|
507
|
+
// Redirect to OIDC logout endpoint
|
|
508
|
+
window.location.href = url;
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
// For JWT or no auth, just clear local state
|
|
512
|
+
const wasJwt = this.authMethod === 'jwt';
|
|
513
|
+
this.authToken = null;
|
|
514
|
+
this.clearOidcTokens();
|
|
515
|
+
this.authMethod = 'none';
|
|
516
|
+
if (this.socket.connected)
|
|
517
|
+
this.socket.disconnect();
|
|
518
|
+
if (typeof window !== 'undefined' && window.location &&
|
|
519
|
+
(window.location.search.includes('code=') || window.location.search.includes('state='))) {
|
|
520
|
+
window.history.replaceState({}, '', window.location.pathname);
|
|
521
|
+
}
|
|
522
|
+
// Emit appropriate logout events
|
|
523
|
+
if (wasJwt) {
|
|
524
|
+
this.emit('jwt-logout');
|
|
525
|
+
this.emit('logout');
|
|
526
|
+
}
|
|
527
|
+
else if (!wasOidc) {
|
|
528
|
+
// No auth case
|
|
529
|
+
this.emit('logout');
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Explicitly logout from OIDC provider
|
|
534
|
+
* Redirects to /end_session endpoint
|
|
535
|
+
*
|
|
536
|
+
* @param {LogoutOptions} [options] - Logout options
|
|
477
537
|
* @returns {Promise<void>}
|
|
478
538
|
*/
|
|
479
|
-
async
|
|
539
|
+
async logoutOidc(options) {
|
|
540
|
+
if (this.authMethod !== 'oidc') {
|
|
541
|
+
throw new Error('Not logged in with OIDC');
|
|
542
|
+
}
|
|
543
|
+
if (!this.oidcConfig?.issuer) {
|
|
544
|
+
throw new Error('OIDC issuer not configured');
|
|
545
|
+
}
|
|
546
|
+
const { redirectUri = this.oidcConfig.redirectUri || window.location.origin, idTokenHint } = options || {};
|
|
547
|
+
let url = `${this.oidcConfig.issuer}/end_session?post_logout_redirect_uri=${encodeURIComponent(redirectUri)}`;
|
|
548
|
+
if (idTokenHint) {
|
|
549
|
+
url += `&id_token_hint=${idTokenHint}`;
|
|
550
|
+
}
|
|
551
|
+
else if (this.oidcIdToken) {
|
|
552
|
+
url += `&id_token_hint=${this.oidcIdToken}`;
|
|
553
|
+
}
|
|
554
|
+
// Clear tokens before redirect
|
|
480
555
|
this.authToken = null;
|
|
481
556
|
this.clearOidcTokens();
|
|
482
557
|
this.authMethod = 'none';
|
|
558
|
+
if (this.socket.connected)
|
|
559
|
+
this.socket.disconnect();
|
|
560
|
+
// Emit OIDC logout event
|
|
561
|
+
this.emit('oidc-logout');
|
|
562
|
+
this.emit('logout');
|
|
563
|
+
window.location.href = url;
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Logout from JWT (client-side only)
|
|
567
|
+
*
|
|
568
|
+
* @returns {Promise<void>}
|
|
569
|
+
*/
|
|
570
|
+
async logoutJwt() {
|
|
571
|
+
if (this.authMethod !== 'jwt') {
|
|
572
|
+
throw new Error('Not logged in with JWT');
|
|
573
|
+
}
|
|
574
|
+
this.authToken = null;
|
|
575
|
+
this.authMethod = 'none';
|
|
483
576
|
if (this.socket.connected)
|
|
484
577
|
this.socket.disconnect();
|
|
485
578
|
if (typeof window !== 'undefined' && window.location &&
|
|
486
579
|
(window.location.search.includes('code=') || window.location.search.includes('state='))) {
|
|
487
580
|
window.history.replaceState({}, '', window.location.pathname);
|
|
488
581
|
}
|
|
582
|
+
// Emit JWT logout event
|
|
583
|
+
if (this.events['jwt-logout']) {
|
|
584
|
+
this.events['jwt-logout']();
|
|
585
|
+
}
|
|
586
|
+
if (this.events['logout']) {
|
|
587
|
+
this.events['logout']();
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Listen for logout events
|
|
592
|
+
*/
|
|
593
|
+
onLogout(callback) {
|
|
594
|
+
this.events['logout'] = callback;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Listen for OIDC logout specifically
|
|
598
|
+
*/
|
|
599
|
+
onOidcLogout(callback) {
|
|
600
|
+
this.events['oidc-logout'] = callback;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Listen for JWT logout specifically
|
|
604
|
+
*/
|
|
605
|
+
onJwtLogout(callback) {
|
|
606
|
+
this.events['jwt-logout'] = callback;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Emit an event
|
|
610
|
+
*/
|
|
611
|
+
emit(event) {
|
|
612
|
+
if (this.events[event]) {
|
|
613
|
+
this.events[event]();
|
|
614
|
+
}
|
|
489
615
|
}
|
|
490
616
|
// OIDC Dynamic Client Registration Methods
|
|
491
617
|
/**
|
|
@@ -742,4 +868,33 @@ export default class docPouchClient {
|
|
|
742
868
|
crypto.getRandomValues(array);
|
|
743
869
|
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
|
|
744
870
|
}
|
|
871
|
+
/**
|
|
872
|
+
* Check if user was just logged out (after redirect from /end_session)
|
|
873
|
+
* Checks URL for logout indicator or checks localStorage
|
|
874
|
+
*
|
|
875
|
+
* @returns {boolean} True if user was just logged out
|
|
876
|
+
*/
|
|
877
|
+
wasJustLoggedOut() {
|
|
878
|
+
// Check URL query parameter
|
|
879
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
880
|
+
if (urlParams.get('logout') === 'true') {
|
|
881
|
+
return true;
|
|
882
|
+
}
|
|
883
|
+
// Check localStorage flag
|
|
884
|
+
const lastAuthMethod = localStorage.getItem('lastAuthMethod');
|
|
885
|
+
const currentAuthMethod = localStorage.getItem('authMethod');
|
|
886
|
+
// If last was OIDC/JWT but current is none, was logged out
|
|
887
|
+
if (lastAuthMethod && currentAuthMethod === null) {
|
|
888
|
+
return true;
|
|
889
|
+
}
|
|
890
|
+
return false;
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Get post_logout_redirect_uri after OIDC logout
|
|
894
|
+
*
|
|
895
|
+
* @returns {string | null} The post logout redirect URI or null if not set
|
|
896
|
+
*/
|
|
897
|
+
getPostLogoutRedirectUri() {
|
|
898
|
+
return localStorage.getItem('postLogoutRedirectUri');
|
|
899
|
+
}
|
|
745
900
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docpouch-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -23,16 +23,16 @@
|
|
|
23
23
|
"description": "Client SDK for DocPouch API - supports JWT and OIDC authentication",
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
26
|
-
"url": "https://github.com/BFH-JTF/docpouch-client"
|
|
26
|
+
"url": "git+https://github.com/BFH-JTF/docpouch-client.git"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/express": "^5.0.6",
|
|
30
30
|
"@types/jest": "^30.0.0",
|
|
31
|
-
"@types/node": "^25.
|
|
31
|
+
"@types/node": "^25.9.1",
|
|
32
32
|
"express": "^5.2.1",
|
|
33
33
|
"jest": "^30.4.2",
|
|
34
34
|
"socket.io": "^4.8.3",
|
|
35
|
-
"ts-jest": "^29.4.
|
|
35
|
+
"ts-jest": "^29.4.10",
|
|
36
36
|
"typescript": "^6.0.3"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
Chat 'ChatTitle(text="I am adding authent…" with OpenCode, isCustom=true)' (09e440bd-c52c-44b9-bba4-01cebc84bd7b)
|
|
2
|
-
Context:
|
|
3
|
-
|
|
4
|
-
Messages: 18
|
|
5
|
-
=================================================================================================================
|
|
6
|
-
|
|
7
|
-
==== RestoredMessage #1 ====
|
|
8
|
-
User:
|
|
9
|
-
I am adding authentication using node-oidcProvider to my app in addition to the already present localStorage solution. To give clients the possibility to register, is it enough to create a call to `this.expressApp.post` and get the necessary information from the client including some kind of secret?
|
|
10
|
-
Attachments:
|
|
11
|
-
Attachment Name: Console Selection
|
|
12
|
-
Attachments Kind: Visible
|
|
13
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
14
|
-
Attachments Text:
|
|
15
|
-
this.expressApp.get
|
|
16
|
-
Attachment Name: Console Selection
|
|
17
|
-
Attachments Kind: Visible
|
|
18
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
19
|
-
Attachments Text:
|
|
20
|
-
validate
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
kotlin.Unit
|
|
24
|
-
|
|
25
|
-
==== RestoredMessage #2 ====
|
|
26
|
-
Assistant:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
kotlin.Unit
|
|
30
|
-
|
|
31
|
-
==== RestoredMessage #3 ====
|
|
32
|
-
User:
|
|
33
|
-
Yes, good idea
|
|
34
|
-
Attachments:
|
|
35
|
-
Attachment Name: Console Selection
|
|
36
|
-
Attachments Kind: Visible
|
|
37
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
38
|
-
Attachments Text:
|
|
39
|
-
validate
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
kotlin.Unit
|
|
43
|
-
|
|
44
|
-
==== RestoredMessage #4 ====
|
|
45
|
-
Assistant:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
kotlin.Unit
|
|
49
|
-
|
|
50
|
-
==== RestoredMessage #5 ====
|
|
51
|
-
User:
|
|
52
|
-
1. I want a controlled registration. I changed initialAccessToken to `process.env.OIDC_REGISTRATION_TOKEN`.
|
|
53
|
-
2. I don't even know what JWKS is, let alone have anything set up for it.
|
|
54
|
-
Yes, please proceed
|
|
55
|
-
Attachments:
|
|
56
|
-
Attachment Name: Console Selection
|
|
57
|
-
Attachments Kind: Visible
|
|
58
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
59
|
-
Attachments Text:
|
|
60
|
-
process.env.OIDC_REGISTRATION_TOKEN
|
|
61
|
-
Attachment Name: Console Selection
|
|
62
|
-
Attachments Kind: Visible
|
|
63
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
64
|
-
Attachments Text:
|
|
65
|
-
validate
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
kotlin.Unit
|
|
69
|
-
|
|
70
|
-
==== RestoredMessage #6 ====
|
|
71
|
-
Assistant:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
kotlin.Unit
|
|
75
|
-
|
|
76
|
-
==== RestoredMessage #7 ====
|
|
77
|
-
User:
|
|
78
|
-
Let's go with a static JWKS for starters. Yes, I would like the clients to have their choice, whether they want to use the localStorage or the OIDC approach for authentication. For both, the clients are expected to build their own login masks.
|
|
79
|
-
If the registration token is not just a random string, I need help, yes.
|
|
80
|
-
Attachments:
|
|
81
|
-
Attachment Name: Console Selection
|
|
82
|
-
Attachments Kind: Visible
|
|
83
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
84
|
-
Attachments Text:
|
|
85
|
-
process.env.OIDC_REGISTRATION_TOKEN
|
|
86
|
-
Attachment Name: Console Selection
|
|
87
|
-
Attachments Kind: Visible
|
|
88
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
89
|
-
Attachments Text:
|
|
90
|
-
validate
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
kotlin.Unit
|
|
94
|
-
|
|
95
|
-
==== RestoredMessage #8 ====
|
|
96
|
-
Assistant:
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
kotlin.Unit
|
|
100
|
-
|
|
101
|
-
==== RestoredMessage #9 ====
|
|
102
|
-
User:
|
|
103
|
-
I am unsure,now. If I give clients these options for auth, is it easier for them, than having to build their own login mask?
|
|
104
|
-
1. The old approach using the token in localStorage.
|
|
105
|
-
2. OIDC and they can use a login mask provided by docPouch.
|
|
106
|
-
Attachments:
|
|
107
|
-
Attachment Name: Console Selection
|
|
108
|
-
Attachments Kind: Visible
|
|
109
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
110
|
-
Attachments Text:
|
|
111
|
-
process.env.OIDC_REGISTRATION_TOKEN
|
|
112
|
-
Attachment Name: Console Selection
|
|
113
|
-
Attachments Kind: Visible
|
|
114
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
115
|
-
Attachments Text:
|
|
116
|
-
validate
|
|
117
|
-
Attachment Name: Console Selection
|
|
118
|
-
Attachments Kind: Visible
|
|
119
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
120
|
-
Attachments Text:
|
|
121
|
-
JWT_SECRET=your-secure-jwt-secret-here
|
|
122
|
-
Attachment Name: Console Selection
|
|
123
|
-
Attachments Kind: Visible
|
|
124
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
125
|
-
Attachments Text:
|
|
126
|
-
NODE_ENV
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
kotlin.Unit
|
|
130
|
-
|
|
131
|
-
==== RestoredMessage #10 ====
|
|
132
|
-
Assistant:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
kotlin.Unit
|
|
136
|
-
|
|
137
|
-
==== RestoredMessage #11 ====
|
|
138
|
-
User:
|
|
139
|
-
I want to offer both choices and build a server-side login page.
|
|
140
|
-
Attachments:
|
|
141
|
-
Attachment Name: Console Selection
|
|
142
|
-
Attachments Kind: Visible
|
|
143
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
144
|
-
Attachments Text:
|
|
145
|
-
process.env.OIDC_REGISTRATION_TOKEN
|
|
146
|
-
Attachment Name: Console Selection
|
|
147
|
-
Attachments Kind: Visible
|
|
148
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
149
|
-
Attachments Text:
|
|
150
|
-
validate
|
|
151
|
-
Attachment Name: Console Selection
|
|
152
|
-
Attachments Kind: Visible
|
|
153
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
154
|
-
Attachments Text:
|
|
155
|
-
JWT_SECRET=your-secure-jwt-secret-here
|
|
156
|
-
Attachment Name: Console Selection
|
|
157
|
-
Attachments Kind: Visible
|
|
158
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
159
|
-
Attachments Text:
|
|
160
|
-
NODE_ENV
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
kotlin.Unit
|
|
164
|
-
|
|
165
|
-
==== RestoredMessage #12 ====
|
|
166
|
-
Assistant:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
kotlin.Unit
|
|
170
|
-
|
|
171
|
-
==== RestoredMessage #13 ====
|
|
172
|
-
User:
|
|
173
|
-
Do I need to update the express routes, so that they are able to validate users using both approaches?
|
|
174
|
-
Attachments:
|
|
175
|
-
Attachment Name: Console Selection
|
|
176
|
-
Attachments Kind: Visible
|
|
177
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
178
|
-
Attachments Text:
|
|
179
|
-
JWT_SECRET=your-secure-jwt-secret-here
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
kotlin.Unit
|
|
183
|
-
|
|
184
|
-
==== RestoredMessage #14 ====
|
|
185
|
-
Assistant:
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
kotlin.Unit
|
|
189
|
-
|
|
190
|
-
==== RestoredMessage #15 ====
|
|
191
|
-
User:
|
|
192
|
-
I am importing interfaces from the docPouch client I have written. I assume I will have to update some of those, as well, when I update the docPouch client, correct?
|
|
193
|
-
Attachments:
|
|
194
|
-
Attachment Name: Console Selection
|
|
195
|
-
Attachments Kind: Visible
|
|
196
|
-
Attachments Source: Other / RestoredChatAttachment
|
|
197
|
-
Attachments Text:
|
|
198
|
-
JWT_SECRET=your-secure-jwt-secret-here
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
kotlin.Unit
|
|
202
|
-
|
|
203
|
-
==== RestoredMessage #16 ====
|
|
204
|
-
Assistant:
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
kotlin.Unit
|
|
208
|
-
|
|
209
|
-
==== UserMessageImpl #17 ====
|
|
210
|
-
User:
|
|
211
|
-
Yes, I would like to go for Option A and the client should offer different methods for the different auth methods and thus explicitly choose. Please make a detailed plan for yourself, so when I load up my docpouch-client project and give you this instruction, you know exactly what to do.
|
|
212
|
-
|
|
213
|
-
kotlin.Unit
|
|
214
|
-
|
|
215
|
-
==== AgentMessage #18 ====
|
|
216
|
-
Assistant:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
Tool use list:
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
kotlin.Unit
|
|
223
|
-
|
package/hff
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
warning: in the working copy of 'README.md', LF will be replaced by CRLF the next time Git touches it
|
|
2
|
-
warning: in the working copy of 'src/index.ts', LF will be replaced by CRLF the next time Git touches it
|
|
3
|
-
warning: in the working copy of 'tsconfig.json', LF will be replaced by CRLF the next time Git touches it
|
|
4
|
-
[1mdiff --git a/package-lock.json b/package-lock.json[m
|
|
5
|
-
[1mindex dacae59..99c15e5 100644[m
|
|
6
|
-
[1m--- a/package-lock.json[m
|
|
7
|
-
[1m+++ b/package-lock.json[m
|
|
8
|
-
[36m@@ -1,12 +1,12 @@[m
|
|
9
|
-
{[m
|
|
10
|
-
"name": "docpouch-client",[m
|
|
11
|
-
[31m- "version": "1.0.0",[m
|
|
12
|
-
[32m+[m[32m "version": "1.0.1",[m
|
|
13
|
-
"lockfileVersion": 3,[m
|
|
14
|
-
"requires": true,[m
|
|
15
|
-
"packages": {[m
|
|
16
|
-
"": {[m
|
|
17
|
-
"name": "docpouch-client",[m
|
|
18
|
-
[31m- "version": "1.0.0",[m
|
|
19
|
-
[32m+[m[32m "version": "1.0.1",[m
|
|
20
|
-
"license": "MIT",[m
|
|
21
|
-
"dependencies": {[m
|
|
22
|
-
"socket.io-client": "^4.8.3"[m
|
|
23
|
-
[1mdiff --git a/package.json b/package.json[m
|
|
24
|
-
[1mindex 47412b6..61174a1 100644[m
|
|
25
|
-
[1m--- a/package.json[m
|
|
26
|
-
[1m+++ b/package.json[m
|
|
27
|
-
[36m@@ -1,6 +1,6 @@[m
|
|
28
|
-
{[m
|
|
29
|
-
"name": "docpouch-client",[m
|
|
30
|
-
[31m- "version": "1.0.1",[m
|
|
31
|
-
[32m+[m[32m "version": "1.0.3",[m
|
|
32
|
-
"main": "dist/index.js",[m
|
|
33
|
-
"types": "dist/index.d.ts",[m
|
|
34
|
-
"exports": {[m
|
|
35
|
-
[1mdiff --git a/src/index.ts b/src/index.ts[m
|
|
36
|
-
[1mindex b9368d4..545dade 100644[m
|
|
37
|
-
[1m--- a/src/index.ts[m
|
|
38
|
-
[1m+++ b/src/index.ts[m
|
|
39
|
-
[36m@@ -358,6 +358,18 @@[m [mexport default class docPouchClient {[m
|
|
40
|
-
[m
|
|
41
|
-
// OIDC Authentication Methods[m
|
|
42
|
-
[m
|
|
43
|
-
[32m+[m[32m /**[m
|
|
44
|
-
[32m+[m[32m * Sets the OIDC configuration to use for the callback and token exchange.[m
|
|
45
|
-
[32m+[m[32m * Call this before {@link handleOidcCallback} if the client was freshly[m
|
|
46
|
-
[32m+[m[32m * instantiated after a page reload (the config is otherwise only set[m
|
|
47
|
-
[32m+[m[32m * internally by {@link loginWithOidc} before the redirect).[m
|
|
48
|
-
[32m+[m[32m *[m
|
|
49
|
-
[32m+[m[32m * @param {I_OidcConfig} config - OIDC provider configuration.[m
|
|
50
|
-
[32m+[m[32m */[m
|
|
51
|
-
[32m+[m[32m setOidcConfig(config: I_OidcConfig): void {[m
|
|
52
|
-
[32m+[m[32m this.oidcConfig = config;[m
|
|
53
|
-
[32m+[m[32m }[m
|
|
54
|
-
[32m+[m
|
|
55
|
-
/**[m
|
|
56
|
-
* Initiates the OIDC authentication flow by redirecting to the authorization endpoint.[m
|
|
57
|
-
*[m
|
|
58
|
-
[36m@@ -373,11 +385,20 @@[m [mexport default class docPouchClient {[m
|
|
59
|
-
this.oidcState = this.generateState();[m
|
|
60
|
-
const codeChallenge = await this.generateCodeChallenge(this.codeVerifier!);[m
|
|
61
|
-
[m
|
|
62
|
-
[32m+[m[32m if (typeof window !== 'undefined' && window.sessionStorage) {[m
|
|
63
|
-
[32m+[m[32m sessionStorage.setItem('docpouch_oidc_state', this.oidcState!);[m
|
|
64
|
-
[32m+[m[32m sessionStorage.setItem('docpouch_oidc_code_verifier', this.codeVerifier!);[m
|
|
65
|
-
[32m+[m[32m sessionStorage.setItem('docpouch_oidc_issuer', config.issuer);[m
|
|
66
|
-
[32m+[m[32m sessionStorage.setItem('docpouch_oidc_client_id', config.clientId);[m
|
|
67
|
-
[32m+[m[32m sessionStorage.setItem('docpouch_oidc_redirect_uri', config.redirectUri);[m
|
|
68
|
-
[32m+[m[32m }[m
|
|
69
|
-
[32m+[m
|
|
70
|
-
[32m+[m[32m const scope = config.scope || config.scopes?.join(' ') || 'openid profile';[m
|
|
71
|
-
const params = new URLSearchParams({[m
|
|
72
|
-
response_type: 'code',[m
|
|
73
|
-
client_id: config.clientId,[m
|
|
74
|
-
redirect_uri: config.redirectUri,[m
|
|
75
|
-
[31m- scope: config.scopes?.join(' ') || 'openid profile',[m
|
|
76
|
-
[32m+[m[32m scope,[m
|
|
77
|
-
state: this.oidcState!,[m
|
|
78
|
-
code_challenge: codeChallenge,[m
|
|
79
|
-
code_challenge_method: 'S256'[m
|
|
80
|
-
[36m@@ -399,6 +420,26 @@[m [mexport default class docPouchClient {[m
|
|
81
|
-
[m
|
|
82
|
-
if (error) throw new Error(`OAuth error: ${error}`);[m
|
|
83
|
-
if (!code || !state) return false;[m
|
|
84
|
-
[32m+[m
|
|
85
|
-
[32m+[m[32m if (typeof window !== 'undefined' && window.sessionStorage) {[m
|
|
86
|
-
[32m+[m[32m this.oidcState = sessionStorage.getItem('docpouch_oidc_state') || this.oidcState;[m
|
|
87
|
-
[32m+[m[32m this.codeVerifier = sessionStorage.getItem('docpouch_oidc_code_verifier') || this.codeVerifier;[m
|
|
88
|
-
[32m+[m[32m sessionStorage.removeItem('docpouch_oidc_state');[m
|
|
89
|
-
[32m+[m[32m sessionStorage.removeItem('docpouch_oidc_code_verifier');[m
|
|
90
|
-
[32m+[m
|
|
91
|
-
[32m+[m[32m if (!this.oidcConfig) {[m
|
|
92
|
-
[32m+[m[32m const issuer = sessionStorage.getItem('docpouch_oidc_issuer');[m
|
|
93
|
-
[32m+[m[32m const clientId = sessionStorage.getItem('docpouch_oidc_client_id');[m
|
|
94
|
-
[32m+[m[32m const redirectUri = sessionStorage.getItem('docpouch_oidc_redirect_uri');[m
|
|
95
|
-
[32m+[m[32m if (issuer && clientId && redirectUri) {[m
|
|
96
|
-
[32m+[m[32m this.oidcConfig = { issuer, clientId, redirectUri };[m
|
|
97
|
-
[32m+[m[32m sessionStorage.removeItem('docpouch_oidc_issuer');[m
|
|
98
|
-
[32m+[m[32m sessionStorage.removeItem('docpouch_oidc_client_id');[m
|
|
99
|
-
[32m+[m[32m sessionStorage.removeItem('docpouch_oidc_redirect_uri');[m
|
|
100
|
-
[32m+[m[32m }[m
|
|
101
|
-
[32m+[m[32m }[m
|
|
102
|
-
[32m+[m[32m }[m
|
|
103
|
-
[32m+[m
|
|
104
|
-
if (state !== this.oidcState) throw new Error('State mismatch');[m
|
|
105
|
-
[m
|
|
106
|
-
const discovery = await this.discoverOidc();[m
|
|
107
|
-
[36m@@ -861,6 +902,7 @@[m [mexport interface I_OidcConfig {[m
|
|
108
|
-
issuer: string;[m
|
|
109
|
-
clientId: string;[m
|
|
110
|
-
redirectUri: string;[m
|
|
111
|
-
[32m+[m[32m scope?: string;[m
|
|
112
|
-
scopes?: string[];[m
|
|
113
|
-
clientSecret?: string;[m
|
|
114
|
-
}[m
|
package/jest.config.cjs
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
preset: 'ts-jest',
|
|
3
|
-
testEnvironment: 'node',
|
|
4
|
-
moduleNameMapper: {
|
|
5
|
-
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
6
|
-
},
|
|
7
|
-
transform: {
|
|
8
|
-
'^.+\\.tsx?$': ['ts-jest', {
|
|
9
|
-
useESM: true,
|
|
10
|
-
}],
|
|
11
|
-
},
|
|
12
|
-
extensionsToTreatAsEsm: ['.ts'],
|
|
13
|
-
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
|
|
14
|
-
testMatch: ['**/__tests__/**/*.ts?(x)', '**/?(*.)+(spec|test).ts?(x)', 'tests/**/*.test.ts'],
|
|
15
|
-
collectCoverage: true,
|
|
16
|
-
coverageDirectory: 'coverage',
|
|
17
|
-
coverageReporters: ['text', 'lcov'],
|
|
18
|
-
};
|