@douvery/auth 0.3.1 → 0.3.3
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/index.d.ts +61 -1
- package/dist/index.js +132 -2
- package/dist/index.js.map +1 -1
- package/dist/qwik/index.d.ts +59 -25
- package/dist/qwik/index.js +154 -59
- package/dist/qwik/index.js.map +1 -1
- package/package.json +4 -3
- package/src/qwik/index.tsx +439 -0
package/dist/index.d.ts
CHANGED
|
@@ -454,5 +454,65 @@ declare class TokenManager {
|
|
|
454
454
|
clearReturnTo(): Promise<void>;
|
|
455
455
|
clearAll(): Promise<void>;
|
|
456
456
|
}
|
|
457
|
+
/**
|
|
458
|
+
* Options for createServerBridgedStorage.
|
|
459
|
+
*
|
|
460
|
+
* Use this when tokens are managed server-side (httpOnly cookies)
|
|
461
|
+
* but the OAuth/PKCE flow needs client-side ephemeral storage.
|
|
462
|
+
*/
|
|
463
|
+
interface ServerBridgedStorageOptions {
|
|
464
|
+
/**
|
|
465
|
+
* Name of a **non-httpOnly** cookie that holds the access token
|
|
466
|
+
* expiration timestamp (in milliseconds). Used to infer whether
|
|
467
|
+
* a valid session exists without exposing the actual tokens.
|
|
468
|
+
*/
|
|
469
|
+
tokenExpirationCookie: string;
|
|
470
|
+
/**
|
|
471
|
+
* Placeholder value returned by `get()` for server-managed keys
|
|
472
|
+
* (accessToken, refreshToken). Signals to the caller that the
|
|
473
|
+
* real token exists but is not readable from JS.
|
|
474
|
+
* @default "__server_managed__"
|
|
475
|
+
*/
|
|
476
|
+
serverManagedPlaceholder?: string;
|
|
477
|
+
/**
|
|
478
|
+
* Enable debug logging.
|
|
479
|
+
* @default false
|
|
480
|
+
*/
|
|
481
|
+
debug?: boolean;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Creates a `TokenStorage` adapter for apps where **tokens are
|
|
485
|
+
* managed server-side** (e.g. httpOnly cookies set by routeLoader$/
|
|
486
|
+
* routeAction$) but the OAuth PKCE flow still needs ephemeral
|
|
487
|
+
* client-side storage for state, nonce, codeVerifier and returnTo.
|
|
488
|
+
*
|
|
489
|
+
* Behaviour per key category:
|
|
490
|
+
*
|
|
491
|
+
* | Category | get() | set() / remove() |
|
|
492
|
+
* |-------------------|------------------------------------------|-------------------|
|
|
493
|
+
* | accessToken | returns placeholder if session is active | no-op (server) |
|
|
494
|
+
* | refreshToken | returns placeholder if session exists | no-op (server) |
|
|
495
|
+
* | idToken | always null | no-op |
|
|
496
|
+
* | expiresAt | reads from expiration cookie | no-op (server) |
|
|
497
|
+
* | state/nonce/etc. | sessionStorage | sessionStorage |
|
|
498
|
+
*
|
|
499
|
+
* @example
|
|
500
|
+
* ```ts
|
|
501
|
+
* import { createServerBridgedStorage } from '@douvery/auth';
|
|
502
|
+
*
|
|
503
|
+
* const bridgedStorage = createServerBridgedStorage({
|
|
504
|
+
* tokenExpirationCookie: 'dou_token_exp',
|
|
505
|
+
* debug: import.meta.env.DEV,
|
|
506
|
+
* });
|
|
507
|
+
*
|
|
508
|
+
* const config: DouveryAuthConfig = {
|
|
509
|
+
* clientId: 'my-app',
|
|
510
|
+
* redirectUri: '/callback',
|
|
511
|
+
* customStorage: bridgedStorage,
|
|
512
|
+
* autoRefresh: false, // server handles refresh
|
|
513
|
+
* };
|
|
514
|
+
* ```
|
|
515
|
+
*/
|
|
516
|
+
declare function createServerBridgedStorage(options: ServerBridgedStorageOptions): TokenStorage;
|
|
457
517
|
|
|
458
|
-
export { type AddAccountOptions, AuthError, type AuthErrorCode, type AuthEvent, type AuthEventHandler, type AuthNavigationOptions, type AuthState, type AuthStatus, type AuthUrl, type CallbackResult, CookieStorage, type DecodedIdToken, DouveryAuthClient, type DouveryAuthConfig, LocalStorage, type LoginOptions, type LogoutOptions, MemoryStorage, type OIDCDiscovery, type PKCEPair, type RecoverAccountOptions, type RegisterOptions, type RevokeTokenOptions, STORAGE_KEYS, type SelectAccountOptions, SessionStorage, type SetupAddressOptions, type SetupPasskeyOptions, type StorageKeys, type TokenInfo, TokenManager, type TokenSet, type TokenStorage, type UpgradeAccountOptions, type User, type VerifyAccountOptions, base64UrlDecode, base64UrlEncode, createDouveryAuth, createStorage, decodeJWT, generateCodeChallenge, generateCodeVerifier, generateNonce, generatePKCEPair, generateState, getTokenExpiration, isTokenExpired, verifyCodeChallenge };
|
|
518
|
+
export { type AddAccountOptions, AuthError, type AuthErrorCode, type AuthEvent, type AuthEventHandler, type AuthNavigationOptions, type AuthState, type AuthStatus, type AuthUrl, type CallbackResult, CookieStorage, type DecodedIdToken, DouveryAuthClient, type DouveryAuthConfig, LocalStorage, type LoginOptions, type LogoutOptions, MemoryStorage, type OIDCDiscovery, type PKCEPair, type RecoverAccountOptions, type RegisterOptions, type RevokeTokenOptions, STORAGE_KEYS, type SelectAccountOptions, type ServerBridgedStorageOptions, SessionStorage, type SetupAddressOptions, type SetupPasskeyOptions, type StorageKeys, type TokenInfo, TokenManager, type TokenSet, type TokenStorage, type UpgradeAccountOptions, type User, type VerifyAccountOptions, base64UrlDecode, base64UrlEncode, createDouveryAuth, createServerBridgedStorage, createStorage, decodeJWT, generateCodeChallenge, generateCodeVerifier, generateNonce, generatePKCEPair, generateState, getTokenExpiration, isTokenExpired, verifyCodeChallenge };
|
package/dist/index.js
CHANGED
|
@@ -286,6 +286,113 @@ var TokenManager = class {
|
|
|
286
286
|
await this.storage.clear();
|
|
287
287
|
}
|
|
288
288
|
};
|
|
289
|
+
var SERVER_TOKEN_KEYS = /* @__PURE__ */ new Set([
|
|
290
|
+
STORAGE_KEYS.accessToken,
|
|
291
|
+
STORAGE_KEYS.refreshToken,
|
|
292
|
+
STORAGE_KEYS.idToken
|
|
293
|
+
]);
|
|
294
|
+
var PKCE_KEYS = /* @__PURE__ */ new Set([
|
|
295
|
+
STORAGE_KEYS.state,
|
|
296
|
+
STORAGE_KEYS.nonce,
|
|
297
|
+
STORAGE_KEYS.codeVerifier,
|
|
298
|
+
STORAGE_KEYS.returnTo
|
|
299
|
+
]);
|
|
300
|
+
function readClientCookie(name) {
|
|
301
|
+
if (typeof document === "undefined") return null;
|
|
302
|
+
const cookies = document.cookie.split(";");
|
|
303
|
+
for (const c of cookies) {
|
|
304
|
+
const [key, ...parts] = c.trim().split("=");
|
|
305
|
+
if (key === name) return decodeURIComponent(parts.join("="));
|
|
306
|
+
}
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
function safeSessionStorage() {
|
|
310
|
+
if (typeof window === "undefined" || typeof sessionStorage === "undefined") {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
return sessionStorage;
|
|
314
|
+
}
|
|
315
|
+
function createServerBridgedStorage(options) {
|
|
316
|
+
const {
|
|
317
|
+
tokenExpirationCookie,
|
|
318
|
+
serverManagedPlaceholder = "__server_managed__",
|
|
319
|
+
debug = false
|
|
320
|
+
} = options;
|
|
321
|
+
function log(msg) {
|
|
322
|
+
if (debug) console.debug(`[ServerBridgedStorage] ${msg}`);
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
get(key) {
|
|
326
|
+
if (key === STORAGE_KEYS.accessToken) {
|
|
327
|
+
const exp = readClientCookie(tokenExpirationCookie);
|
|
328
|
+
if (exp) {
|
|
329
|
+
const ms = parseInt(exp, 10);
|
|
330
|
+
if (!isNaN(ms) && ms > Date.now()) return serverManagedPlaceholder;
|
|
331
|
+
}
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
if (key === STORAGE_KEYS.refreshToken) {
|
|
335
|
+
const exp = readClientCookie(tokenExpirationCookie);
|
|
336
|
+
return exp ? serverManagedPlaceholder : null;
|
|
337
|
+
}
|
|
338
|
+
if (key === STORAGE_KEYS.idToken) return null;
|
|
339
|
+
if (key === STORAGE_KEYS.expiresAt) {
|
|
340
|
+
return readClientCookie(tokenExpirationCookie);
|
|
341
|
+
}
|
|
342
|
+
if (PKCE_KEYS.has(key)) {
|
|
343
|
+
return safeSessionStorage()?.getItem(key) ?? null;
|
|
344
|
+
}
|
|
345
|
+
return safeSessionStorage()?.getItem(key) ?? null;
|
|
346
|
+
},
|
|
347
|
+
set(key, value) {
|
|
348
|
+
if (SERVER_TOKEN_KEYS.has(key) || key === STORAGE_KEYS.expiresAt) {
|
|
349
|
+
log(`Ignoring set("${key}") \u2013 managed by server`);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const ss = safeSessionStorage();
|
|
353
|
+
if (ss) {
|
|
354
|
+
try {
|
|
355
|
+
ss.setItem(key, value);
|
|
356
|
+
} catch (e) {
|
|
357
|
+
if (debug)
|
|
358
|
+
console.warn(
|
|
359
|
+
"[ServerBridgedStorage] sessionStorage.setItem failed:",
|
|
360
|
+
e
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
remove(key) {
|
|
366
|
+
if (SERVER_TOKEN_KEYS.has(key) || key === STORAGE_KEYS.expiresAt) {
|
|
367
|
+
log(`Ignoring remove("${key}") \u2013 managed by server`);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const ss = safeSessionStorage();
|
|
371
|
+
if (ss) {
|
|
372
|
+
try {
|
|
373
|
+
ss.removeItem(key);
|
|
374
|
+
} catch (e) {
|
|
375
|
+
if (debug)
|
|
376
|
+
console.warn(
|
|
377
|
+
"[ServerBridgedStorage] sessionStorage.removeItem failed:",
|
|
378
|
+
e
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
clear() {
|
|
384
|
+
const ss = safeSessionStorage();
|
|
385
|
+
if (!ss) return;
|
|
386
|
+
for (const key of PKCE_KEYS) {
|
|
387
|
+
try {
|
|
388
|
+
ss.removeItem(key);
|
|
389
|
+
} catch {
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
log("PKCE ephemeral data cleared from sessionStorage");
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}
|
|
289
396
|
|
|
290
397
|
// src/client.ts
|
|
291
398
|
var DEFAULT_ISSUER = "https://auth.douvery.com";
|
|
@@ -866,6 +973,7 @@ var DouveryAuthClient = class {
|
|
|
866
973
|
async getDiscovery() {
|
|
867
974
|
if (this.discovery) return this.discovery;
|
|
868
975
|
const discoveryUrl = `${this.config.issuer}/.well-known/openid-configuration`;
|
|
976
|
+
this.log("Fetching discovery from:", discoveryUrl);
|
|
869
977
|
const response = await fetch(discoveryUrl);
|
|
870
978
|
if (!response.ok) {
|
|
871
979
|
throw new AuthError(
|
|
@@ -873,7 +981,29 @@ var DouveryAuthClient = class {
|
|
|
873
981
|
"Failed to fetch discovery document"
|
|
874
982
|
);
|
|
875
983
|
}
|
|
876
|
-
|
|
984
|
+
const doc = await response.json();
|
|
985
|
+
const docIssuer = doc.issuer;
|
|
986
|
+
const configIssuer = this.config.issuer;
|
|
987
|
+
if (docIssuer && docIssuer !== configIssuer) {
|
|
988
|
+
this.log(
|
|
989
|
+
`Rewriting discovery endpoints: "${docIssuer}" -> "${configIssuer}"`
|
|
990
|
+
);
|
|
991
|
+
const rewrite = (url) => url.replace(docIssuer, configIssuer);
|
|
992
|
+
doc.issuer = configIssuer;
|
|
993
|
+
doc.authorization_endpoint = rewrite(doc.authorization_endpoint);
|
|
994
|
+
doc.token_endpoint = rewrite(doc.token_endpoint);
|
|
995
|
+
if (doc.userinfo_endpoint)
|
|
996
|
+
doc.userinfo_endpoint = rewrite(doc.userinfo_endpoint);
|
|
997
|
+
if (doc.end_session_endpoint)
|
|
998
|
+
doc.end_session_endpoint = rewrite(doc.end_session_endpoint);
|
|
999
|
+
if (doc.jwks_uri) doc.jwks_uri = rewrite(doc.jwks_uri);
|
|
1000
|
+
if (doc.revocation_endpoint)
|
|
1001
|
+
doc.revocation_endpoint = rewrite(doc.revocation_endpoint);
|
|
1002
|
+
if (doc.introspection_endpoint)
|
|
1003
|
+
doc.introspection_endpoint = rewrite(doc.introspection_endpoint);
|
|
1004
|
+
}
|
|
1005
|
+
this.log("authorization_endpoint:", doc.authorization_endpoint);
|
|
1006
|
+
this.discovery = doc;
|
|
877
1007
|
return this.discovery;
|
|
878
1008
|
}
|
|
879
1009
|
setupAutoRefresh() {
|
|
@@ -931,6 +1061,6 @@ function createDouveryAuth(config) {
|
|
|
931
1061
|
return new DouveryAuthClient(config);
|
|
932
1062
|
}
|
|
933
1063
|
|
|
934
|
-
export { AuthError, CookieStorage, DouveryAuthClient, LocalStorage, MemoryStorage, STORAGE_KEYS, SessionStorage, TokenManager, base64UrlDecode, base64UrlEncode, createDouveryAuth, createStorage, decodeJWT, generateCodeChallenge, generateCodeVerifier, generateNonce, generatePKCEPair, generateState, getTokenExpiration, isTokenExpired, verifyCodeChallenge };
|
|
1064
|
+
export { AuthError, CookieStorage, DouveryAuthClient, LocalStorage, MemoryStorage, STORAGE_KEYS, SessionStorage, TokenManager, base64UrlDecode, base64UrlEncode, createDouveryAuth, createServerBridgedStorage, createStorage, decodeJWT, generateCodeChallenge, generateCodeVerifier, generateNonce, generatePKCEPair, generateState, getTokenExpiration, isTokenExpired, verifyCodeChallenge };
|
|
935
1065
|
//# sourceMappingURL=index.js.map
|
|
936
1066
|
//# sourceMappingURL=index.js.map
|