@tidecloak/js 0.13.11 → 0.13.14

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.
@@ -4,9 +4,10 @@ declare const IAMServiceInstance: IAMService;
4
4
  /**
5
5
  * Singleton IAMService wrapping the TideCloak client.
6
6
  *
7
- * Supports two modes:
7
+ * Supports three modes:
8
8
  * - **Front-channel mode**: Browser handles all token operations (standard OIDC)
9
9
  * - **Hybrid/BFF mode**: Browser handles PKCE, backend exchanges code for tokens (more secure)
10
+ * - **Native mode**: External browser for login, app handles tokens via adapter (Electron, Tauri, React Native)
10
11
  *
11
12
  * ---
12
13
  * ## Front-channel Mode
@@ -122,6 +123,19 @@ declare class IAMService {
122
123
  error: null;
123
124
  errorDescription: null;
124
125
  } | null;
126
+ _nativeAdapter: any;
127
+ _nativeAuthenticated: boolean;
128
+ _nativeTokens: any;
129
+ _nativeCallbackUnsubscribe: any;
130
+ _nativeCallbackHandled: boolean;
131
+ _nativeCallbackPromise: any;
132
+ _nativeCallbackProcessing: boolean;
133
+ _nativeDoken: any;
134
+ _nativeDokenParsed: Object | null;
135
+ _nativeVoucher: any;
136
+ _nativeRequestEnclave: RequestEnclave | null;
137
+ _nativeEncryptionCallbackUnsubscribe: any;
138
+ _pendingEncryptionRequests: Map<any, any>;
125
139
  /**
126
140
  * Register an event listener.
127
141
  * @param {'ready'|'initError'|'authSuccess'|'authError'|'authRefreshSuccess'|'authRefreshError'|'logout'|'tokenExpired'} event
@@ -143,6 +157,11 @@ declare class IAMService {
143
157
  * @returns {boolean}
144
158
  */
145
159
  isHybridMode(): boolean;
160
+ /**
161
+ * Check if running in native mode.
162
+ * @returns {boolean}
163
+ */
164
+ isNativeMode(): boolean;
146
165
  /**
147
166
  * Load TideCloak configuration and instantiate the client once.
148
167
  * @param {Object} config - TideCloak configuration object.
@@ -161,7 +180,7 @@ declare class IAMService {
161
180
  private getTideCloakClient;
162
181
  /** @returns {Object} Loaded config */
163
182
  getConfig(): Object;
164
- /** @returns {boolean} Whether there's a valid token (or session in hybrid mode) */
183
+ /** @returns {boolean} Whether there's a valid token (or session in hybrid/native mode) */
165
184
  isLoggedIn(): boolean;
166
185
  /**
167
186
  * Get valid token (refreshing if needed).
@@ -237,24 +256,36 @@ declare class IAMService {
237
256
  /**
238
257
  * Start login redirect.
239
258
  * In hybrid mode, initiates PKCE flow and redirects to IdP.
240
- * @param {string} [returnUrl] - URL to redirect to after successful auth (hybrid mode only)
259
+ * In native mode, opens external browser with auth URL.
260
+ * @param {string} [returnUrl] - URL to redirect to after successful auth (hybrid/native mode)
241
261
  */
242
262
  doLogin(returnUrl?: string): Promise<void> | undefined;
243
263
  /**
244
264
  * Encrypt data via adapter.
245
265
  * Not available in hybrid mode (encryption requires client-side doken).
266
+ * @param {{ data: string | Uint8Array, tags: string[] }[]} data - Array of objects to encrypt
267
+ * @returns {Promise<(string | Uint8Array)[]>} Array of encrypted values
246
268
  */
247
- doEncrypt(data: any): Promise<(string | Uint8Array<ArrayBufferLike>)[]>;
269
+ doEncrypt(data: {
270
+ data: string | Uint8Array;
271
+ tags: string[];
272
+ }[]): Promise<(string | Uint8Array)[]>;
248
273
  /**
249
274
  * Decrypt data via adapter.
250
275
  * Not available in hybrid mode (decryption requires client-side doken).
276
+ * @param {{ encrypted: string | Uint8Array, tags: string[] }[]} data - Array of objects to decrypt
277
+ * @returns {Promise<(string | Uint8Array)[]>} Array of decrypted values
251
278
  */
252
- doDecrypt(data: any): Promise<(string | Uint8Array<ArrayBufferLike>)[]>;
279
+ doDecrypt(data: {
280
+ encrypted: string | Uint8Array;
281
+ tags: string[];
282
+ }[]): Promise<(string | Uint8Array)[]>;
253
283
  /**
254
284
  * Logout, clear cookie/session, then redirect.
255
285
  * In hybrid mode, clears local state and emits logout event.
286
+ * In native mode, deletes tokens via adapter and emits logout event.
256
287
  */
257
- doLogout(): void;
288
+ doLogout(): Promise<void>;
258
289
  /**
259
290
  * Base URL for Tidecloak realm (no trailing slash).
260
291
  * In hybrid mode returns empty string.
@@ -324,5 +355,128 @@ declare class IAMService {
324
355
  * @returns {Promise<{handled: boolean, authenticated: boolean, returnUrl: string}>}
325
356
  */
326
357
  private _handleHybridRedirectCallback;
358
+ /**
359
+ * Get OIDC configuration from the native config.
360
+ * @private
361
+ * @returns {{ authServerUrl: string, realm: string, clientId: string, scope: string }}
362
+ */
363
+ private _getNativeOIDCConfig;
364
+ /**
365
+ * Get encryption configuration from the native config.
366
+ * Automatically selects clientOriginAuth based on window.location.origin.
367
+ * @private
368
+ * @returns {{ vendorId: string, homeOrkUrl: string, clientOriginAuth: string } | null}
369
+ */
370
+ private _getNativeEncryptionConfig;
371
+ /**
372
+ * Start native login flow: generate PKCE, open external browser with auth URL.
373
+ * @private
374
+ * @param {string} returnUrl - URL to redirect to after successful auth
375
+ */
376
+ private _startNativeLogin;
377
+ /**
378
+ * Handle native auth callback: exchange code for tokens.
379
+ * @private
380
+ * @param {string} code - Authorization code from IdP
381
+ * @param {string} [voucher] - Optional voucher fetched during login (for encryption)
382
+ */
383
+ private _handleNativeCallback;
384
+ /**
385
+ * Refresh native token using refresh token.
386
+ * @private
387
+ * @param {string} refreshToken - The refresh token
388
+ * @returns {Promise<Object>} New token data
389
+ */
390
+ private _refreshNativeToken;
391
+ /**
392
+ * Initialize the native RequestEnclave for encryption/decryption.
393
+ * @private
394
+ * @param {string} voucherDataUrl - Pre-fetched voucher as data URL
395
+ */
396
+ private _initNativeRequestEnclave;
397
+ /**
398
+ * Build the encryption page URL for external browser.
399
+ * This page is hosted on the TideCloak server and has session cookies.
400
+ * @private
401
+ * @param {string} operation - 'encrypt' or 'decrypt'
402
+ * @param {string} requestId - Unique request ID
403
+ * @param {string} dataBase64 - Base64-encoded data to process
404
+ * @param {string} tagsJson - JSON-encoded tags array
405
+ * @param {string} callbackUrl - URL to redirect with result
406
+ * @returns {string} URL to open in external browser
407
+ */
408
+ private _buildEncryptionPageUrl;
409
+ /**
410
+ * Perform an encryption operation via external browser.
411
+ * @private
412
+ * @param {'encrypt' | 'decrypt'} operation - The operation to perform
413
+ * @param {string} dataBase64 - Base64-encoded data to process
414
+ * @param {string[]} tags - Tags for the operation
415
+ * @returns {Promise<string>} Base64-encoded result
416
+ */
417
+ private _doExternalBrowserOperation;
418
+ /**
419
+ * Get the voucher URL for native mode.
420
+ * @private
421
+ * @returns {string} Voucher URL
422
+ */
423
+ private _getNativeVoucherUrl;
424
+ /**
425
+ * Check if user has a realm role (native mode helper).
426
+ * @private
427
+ * @param {string} role - Role to check
428
+ * @returns {boolean}
429
+ */
430
+ private _nativeHasRealmRole;
431
+ /**
432
+ * Native mode encryption using RequestEnclave.
433
+ * Uses either a pre-fetched voucher (as data URL) or the live voucherURL
434
+ * that the ORK iframe will fetch with session cookies.
435
+ * @private
436
+ * @param {{ data: string | Uint8Array, tags: string[] }[]} toEncrypt
437
+ * @returns {Promise<(string | Uint8Array)[]>}
438
+ */
439
+ private _nativeEncrypt;
440
+ /**
441
+ * Native mode decryption using RequestEnclave.
442
+ * Uses either a pre-fetched voucher (as data URL) or the live voucherURL
443
+ * that the ORK iframe will fetch with session cookies.
444
+ * @private
445
+ * @param {{ encrypted: string | Uint8Array, tags: string[] }[]} toDecrypt
446
+ * @returns {Promise<(string | Uint8Array)[]>}
447
+ */
448
+ private _nativeDecrypt;
449
+ /**
450
+ * Convert string to Uint8Array.
451
+ * @private
452
+ */
453
+ private _stringToUint8Array;
454
+ /**
455
+ * Convert Uint8Array to string.
456
+ * @private
457
+ */
458
+ private _stringFromUint8Array;
459
+ /**
460
+ * Convert bytes to base64.
461
+ * @private
462
+ */
463
+ private _bytesToBase64;
464
+ /**
465
+ * Convert base64 to bytes.
466
+ * @private
467
+ */
468
+ private _base64ToBytes;
469
+ /**
470
+ * Parse a JWT token and return its payload.
471
+ * @private
472
+ * @param {string} token - JWT token string
473
+ * @returns {Object|null} Parsed token payload or null on error
474
+ */
475
+ private _parseToken;
476
+ /**
477
+ * Cleanup native mode resources.
478
+ */
479
+ destroy(): void;
327
480
  }
328
481
  import TideCloak from "../lib/tidecloak.js";
482
+ import { RequestEnclave } from "../lib/tidecloak.js";
@@ -1,3 +1,9 @@
1
1
  export { default as IAMService } from "./IAMService.js";
2
+ export type NativeAdapter = import("./types.js").NativeAdapter;
3
+ export type NativeTokenData = import("./types.js").NativeTokenData;
4
+ export type NativeAuthCallbackResult = import("./types.js").NativeAuthCallbackResult;
5
+ export type NativeEncryptionCallbackResult = import("./types.js").NativeEncryptionCallbackResult;
6
+ export type NativeConfig = import("./types.js").NativeConfig;
2
7
  export { default as TideCloak, RequestEnclave, ApprovalEnclaveNew } from "../lib/tidecloak.js";
3
8
  export { TideMemory, BaseTideRequest } from "heimdall-tide";
9
+ export { default as AdminAPI, AdminAPI as AdminAPIClass } from "./AdminAPI.js";
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Type definitions for @tidecloak/js native mode
3
+ */
4
+ /**
5
+ * Token data for native mode storage.
6
+ */
7
+ export interface NativeTokenData {
8
+ accessToken: string;
9
+ refreshToken: string;
10
+ idToken?: string;
11
+ /** Tide doken (delegated token) for encryption/decryption operations */
12
+ doken?: string;
13
+ expiresAt: number;
14
+ }
15
+ /**
16
+ * Auth callback result from native app.
17
+ */
18
+ export interface NativeAuthCallbackResult {
19
+ code?: string;
20
+ error?: string;
21
+ errorDescription?: string;
22
+ }
23
+ /**
24
+ * Native adapter interface for platform-specific operations.
25
+ *
26
+ * This is the MINIMAL interface developers must implement for their platform.
27
+ * The SDK handles everything else (encryption, token management, etc.).
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * // Electron example - minimal implementation
32
+ * const adapter: NativeAdapter = {
33
+ * getRedirectUri: () => 'myapp://auth/callback',
34
+ * openExternalUrl: (url) => shell.openExternal(url),
35
+ * onAuthCallback: (callback) => {
36
+ * ipcRenderer.on('auth-callback', (_, data) => callback(data));
37
+ * return () => ipcRenderer.off('auth-callback');
38
+ * },
39
+ * saveTokens: (tokens) => store.set('tokens', tokens),
40
+ * getTokens: () => store.get('tokens'),
41
+ * deleteTokens: () => store.delete('tokens'),
42
+ * };
43
+ * ```
44
+ */
45
+ export interface NativeAdapter {
46
+ /** Get the redirect URI for this platform (can be async for dynamic URIs) */
47
+ getRedirectUri: () => string | Promise<string>;
48
+ /** Open a URL in the external browser or popup window */
49
+ openExternalUrl: (url: string) => Promise<void>;
50
+ /** Subscribe to auth callbacks - returns cleanup function */
51
+ onAuthCallback: (callback: (result: NativeAuthCallbackResult) => void) => () => void;
52
+ /** Store tokens securely on the device */
53
+ saveTokens: (tokens: NativeTokenData) => Promise<boolean>;
54
+ /** Retrieve stored tokens */
55
+ getTokens: () => Promise<NativeTokenData | null>;
56
+ /** Delete stored tokens (logout) */
57
+ deleteTokens: () => Promise<boolean>;
58
+ }
59
+ /**
60
+ * Native mode configuration.
61
+ * All TideCloak configuration is here - the adapter only handles platform-specific operations.
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * import adapterConfig from './adapter.json';
66
+ *
67
+ * const config: NativeConfig = {
68
+ * authMode: 'native',
69
+ * adapter: myAdapter,
70
+ * // Spread the adapter.json config - it has all the TideCloak settings
71
+ * ...adapterConfig,
72
+ * };
73
+ * ```
74
+ */
75
+ export interface NativeConfig {
76
+ /** Must be "native" for native mode */
77
+ authMode: "native";
78
+ /** Native adapter with platform-specific implementations */
79
+ adapter: NativeAdapter;
80
+ /** Auth server URL (e.g., "http://localhost:8080") */
81
+ "auth-server-url": string;
82
+ /** Realm name */
83
+ realm: string;
84
+ /** Client ID (resource in adapter.json) */
85
+ resource: string;
86
+ /** Tide vendor ID for encryption operations */
87
+ vendorId?: string;
88
+ /** Home ORK URL (e.g., "https://ork1.tideprotocol.com") */
89
+ homeOrkUrl?: string;
90
+ /**
91
+ * Client origin authentication signatures.
92
+ * These are keyed by origin (e.g., "client-origin-auth-http://localhost:5173").
93
+ * The SDK automatically selects the right one based on window.location.origin.
94
+ */
95
+ [key: `client-origin-auth-${string}`]: string;
96
+ /** Session mode: 'online' (default) validates tokens, 'offline' accepts stored tokens */
97
+ sessionMode?: 'online' | 'offline';
98
+ /** OAuth scopes (defaults to "openid profile email") */
99
+ scope?: string;
100
+ /** JWK for token verification (from adapter.json) */
101
+ jwk?: {
102
+ keys: Array<{
103
+ kid: string;
104
+ kty: string;
105
+ alg: string;
106
+ use: string;
107
+ crv?: string;
108
+ x?: string;
109
+ [key: string]: unknown;
110
+ }>;
111
+ };
112
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Type definitions for @tidecloak/js native mode
3
+ */
4
+ /**
5
+ * Token data for native mode storage.
6
+ */
7
+ export interface NativeTokenData {
8
+ accessToken: string;
9
+ refreshToken: string;
10
+ idToken?: string;
11
+ /** Tide doken (delegated token) for encryption/decryption operations */
12
+ doken?: string;
13
+ expiresAt: number;
14
+ }
15
+ /**
16
+ * Auth callback result from native app.
17
+ */
18
+ export interface NativeAuthCallbackResult {
19
+ code?: string;
20
+ error?: string;
21
+ errorDescription?: string;
22
+ }
23
+ /**
24
+ * Native adapter interface for platform-specific operations.
25
+ *
26
+ * This is the MINIMAL interface developers must implement for their platform.
27
+ * The SDK handles everything else (encryption, token management, etc.).
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * // Electron example - minimal implementation
32
+ * const adapter: NativeAdapter = {
33
+ * getRedirectUri: () => 'myapp://auth/callback',
34
+ * openExternalUrl: (url) => shell.openExternal(url),
35
+ * onAuthCallback: (callback) => {
36
+ * ipcRenderer.on('auth-callback', (_, data) => callback(data));
37
+ * return () => ipcRenderer.off('auth-callback');
38
+ * },
39
+ * saveTokens: (tokens) => store.set('tokens', tokens),
40
+ * getTokens: () => store.get('tokens'),
41
+ * deleteTokens: () => store.delete('tokens'),
42
+ * };
43
+ * ```
44
+ */
45
+ export interface NativeAdapter {
46
+ /** Get the redirect URI for this platform (can be async for dynamic URIs) */
47
+ getRedirectUri: () => string | Promise<string>;
48
+ /** Open a URL in the external browser or popup window */
49
+ openExternalUrl: (url: string) => Promise<void>;
50
+ /** Subscribe to auth callbacks - returns cleanup function */
51
+ onAuthCallback: (callback: (result: NativeAuthCallbackResult) => void) => () => void;
52
+ /** Store tokens securely on the device */
53
+ saveTokens: (tokens: NativeTokenData) => Promise<boolean>;
54
+ /** Retrieve stored tokens */
55
+ getTokens: () => Promise<NativeTokenData | null>;
56
+ /** Delete stored tokens (logout) */
57
+ deleteTokens: () => Promise<boolean>;
58
+ }
59
+ /**
60
+ * Native mode configuration.
61
+ * All TideCloak configuration is here - the adapter only handles platform-specific operations.
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * import adapterConfig from './adapter.json';
66
+ *
67
+ * const config: NativeConfig = {
68
+ * authMode: 'native',
69
+ * adapter: myAdapter,
70
+ * // Spread the adapter.json config - it has all the TideCloak settings
71
+ * ...adapterConfig,
72
+ * };
73
+ * ```
74
+ */
75
+ export interface NativeConfig {
76
+ /** Must be "native" for native mode */
77
+ authMode: "native";
78
+ /** Native adapter with platform-specific implementations */
79
+ adapter: NativeAdapter;
80
+ /** Auth server URL (e.g., "http://localhost:8080") */
81
+ "auth-server-url": string;
82
+ /** Realm name */
83
+ realm: string;
84
+ /** Client ID (resource in adapter.json) */
85
+ resource: string;
86
+ /** Tide vendor ID for encryption operations */
87
+ vendorId?: string;
88
+ /** Home ORK URL (e.g., "https://ork1.tideprotocol.com") */
89
+ homeOrkUrl?: string;
90
+ /**
91
+ * Client origin authentication signatures.
92
+ * These are keyed by origin (e.g., "client-origin-auth-http://localhost:5173").
93
+ * The SDK automatically selects the right one based on window.location.origin.
94
+ */
95
+ [key: `client-origin-auth-${string}`]: string;
96
+ /** Session mode: 'online' (default) validates tokens, 'offline' accepts stored tokens */
97
+ sessionMode?: 'online' | 'offline';
98
+ /** OAuth scopes (defaults to "openid profile email") */
99
+ scope?: string;
100
+ /** JWK for token verification (from adapter.json) */
101
+ jwk?: {
102
+ keys: Array<{
103
+ kid: string;
104
+ kty: string;
105
+ alg: string;
106
+ use: string;
107
+ crv?: string;
108
+ x?: string;
109
+ [key: string]: unknown;
110
+ }>;
111
+ };
112
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tidecloak/js",
3
- "version": "0.13.11",
3
+ "version": "0.13.14",
4
4
  "type": "module",
5
5
  "main": "dist/cjs/src/index.js",
6
6
  "module": "dist/esm/src/index.js",
@@ -32,6 +32,6 @@
32
32
  "silent-check-sso.html"
33
33
  ],
34
34
  "dependencies": {
35
- "heimdall-tide": "^0.13.11"
35
+ "heimdall-tide": "^0.13.14"
36
36
  }
37
37
  }