docpouch-client 1.0.4 → 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/coverage/lcov-report/index.html +19 -19
- package/coverage/lcov.info +667 -534
- package/dist/index.d.ts +56 -1
- package/dist/index.js +157 -7
- package/package.json +1 -1
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,10 +484,32 @@ 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
|
|
477
488
|
* @returns {Promise<void>}
|
|
478
489
|
*/
|
|
479
|
-
async logout() {
|
|
490
|
+
async logout(options) {
|
|
480
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';
|
|
481
513
|
this.authToken = null;
|
|
482
514
|
this.clearOidcTokens();
|
|
483
515
|
this.authMethod = 'none';
|
|
@@ -487,9 +519,98 @@ export default class docPouchClient {
|
|
|
487
519
|
(window.location.search.includes('code=') || window.location.search.includes('state='))) {
|
|
488
520
|
window.history.replaceState({}, '', window.location.pathname);
|
|
489
521
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
|
537
|
+
* @returns {Promise<void>}
|
|
538
|
+
*/
|
|
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
|
|
555
|
+
this.authToken = null;
|
|
556
|
+
this.clearOidcTokens();
|
|
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';
|
|
576
|
+
if (this.socket.connected)
|
|
577
|
+
this.socket.disconnect();
|
|
578
|
+
if (typeof window !== 'undefined' && window.location &&
|
|
579
|
+
(window.location.search.includes('code=') || window.location.search.includes('state='))) {
|
|
580
|
+
window.history.replaceState({}, '', window.location.pathname);
|
|
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]();
|
|
493
614
|
}
|
|
494
615
|
}
|
|
495
616
|
// OIDC Dynamic Client Registration Methods
|
|
@@ -747,4 +868,33 @@ export default class docPouchClient {
|
|
|
747
868
|
crypto.getRandomValues(array);
|
|
748
869
|
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
|
|
749
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
|
+
}
|
|
750
900
|
}
|