@molecule/app-auth 1.2.2 → 1.3.1
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/README.md +150 -42
- package/dist/browser-storage.d.ts +89 -0
- package/dist/browser-storage.d.ts.map +1 -0
- package/dist/browser-storage.js +163 -0
- package/dist/browser-storage.js.map +1 -0
- package/dist/index.d.ts +40 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -19
- package/dist/index.js.map +1 -1
- package/dist/token.d.ts +4 -9
- package/dist/token.d.ts.map +1 -1
- package/dist/token.js +4 -9
- package/dist/token.js.map +1 -1
- package/dist/types.d.ts +36 -17
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,15 +3,11 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
|
3
3
|
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
4
|
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
5
|
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
-
Generated: 2026-10-
|
|
6
|
+
Generated: 2026-10-17T07:07:31.667Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/app-auth
|
|
10
10
|
|
|
11
|
-
> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
|
|
12
|
-
> It is written to be read by coding agents as much as by people, and is generated from this
|
|
13
|
-
> package's source — edit `src/index.ts` JSDoc, not this file.
|
|
14
|
-
|
|
15
11
|
Client-side authentication interface for molecule.dev.
|
|
16
12
|
|
|
17
13
|
Provides a unified auth API that works across different auth strategies
|
|
@@ -21,6 +17,10 @@ client; `setClient`/`getClient` bond it; `login`/`logout`/`register`/
|
|
|
21
17
|
bindings (e.g. `AuthProvider`/`useAuth` in `@molecule/app-react`) wrap the
|
|
22
18
|
same client.
|
|
23
19
|
|
|
20
|
+
> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
|
|
21
|
+
> It is written to be read by coding agents as much as by people, and is generated from this
|
|
22
|
+
> package's source — edit `src/index.ts` JSDoc, not this file.
|
|
23
|
+
|
|
24
24
|
## Quick Start
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
@@ -50,6 +50,30 @@ npm install @molecule/app-auth @molecule/app-bond @molecule/app-i18n @molecule/a
|
|
|
50
50
|
|
|
51
51
|
### Interfaces
|
|
52
52
|
|
|
53
|
+
#### `BrowserStorageAdapterOptions`
|
|
54
|
+
|
|
55
|
+
How {@link createBrowserStorageAdapter} picks the store it writes to.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
interface BrowserStorageAdapterOptions {
|
|
59
|
+
/**
|
|
60
|
+
* The Web Storage area to persist to (default `'local'`).
|
|
61
|
+
*
|
|
62
|
+
* `'session'` is the narrower choice: a reload keeps the session, closing the
|
|
63
|
+
* tab ends it. Pick it when the app only has to survive navigations within one
|
|
64
|
+
* session — which is all a `page.reload()` asks for.
|
|
65
|
+
*/
|
|
66
|
+
kind?: BrowserStorageKind
|
|
67
|
+
/**
|
|
68
|
+
* A store to use instead of resolving `window.localStorage` /
|
|
69
|
+
* `window.sessionStorage` (a test double, a namespaced wrapper, or the
|
|
70
|
+
* `Storage` object another library exposes). Anything with `getItem`/
|
|
71
|
+
* `setItem`/`removeItem` does.
|
|
72
|
+
*/
|
|
73
|
+
storage?: StorageAdapter
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
53
77
|
#### `UserProfile`
|
|
54
78
|
|
|
55
79
|
User profile information.
|
|
@@ -355,6 +379,12 @@ interface AuthClient<T = UserProfile> {
|
|
|
355
379
|
*
|
|
356
380
|
* Optional: a provider that restores no session has nothing to wait for. Without it, an
|
|
357
381
|
* HTTP client bonded to that provider sends first-paint requests unauthenticated.
|
|
382
|
+
*
|
|
383
|
+
* A provider whose restore sends a request THROUGH the gated HTTP client must send that
|
|
384
|
+
* request with `skipAuthGate: true` (`RequestConfig` in `@molecule/app-http`): the gate
|
|
385
|
+
* waits on this promise, so holding the restore's own request makes the gate wait on
|
|
386
|
+
* itself and stalls every request it holds until it times out. `createJWTAuthClient`'s
|
|
387
|
+
* restore does not need it — it uses `fetch`, not the bonded client.
|
|
358
388
|
*/
|
|
359
389
|
whenRestored?(): Promise<void>
|
|
360
390
|
|
|
@@ -437,10 +467,10 @@ interface AuthClientConfig {
|
|
|
437
467
|
|
|
438
468
|
/**
|
|
439
469
|
* Current-user endpoint for session restore (default `/users/me`). Called by
|
|
440
|
-
* `initialize()` with credentials to re-establish the session
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
*
|
|
470
|
+
* `initialize()` with credentials to re-establish the session after a full page
|
|
471
|
+
* load when the token did not survive the reload itself — i.e. when `storage` is
|
|
472
|
+
* `'memory'` and the API sets an httpOnly session cookie. Must return the user
|
|
473
|
+
* (as `user` or `props`).
|
|
444
474
|
*/
|
|
445
475
|
currentUserEndpoint?: string
|
|
446
476
|
|
|
@@ -476,23 +506,36 @@ interface AuthClientConfig {
|
|
|
476
506
|
mapAuthResponse?: (data: unknown) => AuthResult<UserProfile>
|
|
477
507
|
|
|
478
508
|
/**
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
*
|
|
509
|
+
* Where the access/refresh token and the cached user are kept — the field that
|
|
510
|
+
* decides whether a page reload keeps the user signed in.
|
|
511
|
+
*
|
|
512
|
+
* - `'memory'` (the client's default): a process-local store, lost on reload.
|
|
513
|
+
* Correct when the API sets an httpOnly session cookie, which `initialize()`
|
|
514
|
+
* then restores through {@link AuthClientConfig.currentUserEndpoint} — the
|
|
515
|
+
* strongest configuration, because no script can read the cookie.
|
|
516
|
+
* - a `StorageAdapter`: the token survives the reload itself. The browser
|
|
517
|
+
* adapter is `createBrowserStorageAdapter()` (from `@molecule/app-auth`), and
|
|
518
|
+
* the scaffold's generated auth bond (`src/bonds/auth-default.ts`) passes it;
|
|
519
|
+
* `src/config.ts` leaves `storage` out on purpose. A bearer token in Web
|
|
520
|
+
* Storage is readable by any script on the origin, so an XSS can steal it; see
|
|
521
|
+
* that function's `@remarks` for the trade and for the cookie alternative.
|
|
522
|
+
*
|
|
523
|
+
* Any adapter with `getItem`/`setItem`/`removeItem` works — the methods are
|
|
524
|
+
* SYNCHRONOUS, so the async `@molecule/app-storage` provider
|
|
525
|
+
* (`getProvider()`, whose `get()` returns a Promise) is NOT one: wrap the
|
|
526
|
+
* `Storage` object it was built on (`createBrowserStorageAdapter({ storage })`),
|
|
527
|
+
* or store a different way.
|
|
482
528
|
*
|
|
483
529
|
* @example
|
|
484
530
|
* ```typescript
|
|
485
|
-
*
|
|
486
|
-
* storage: 'memory'
|
|
531
|
+
* import { createBrowserStorageAdapter } from '@molecule/app-auth'
|
|
487
532
|
*
|
|
488
|
-
* //
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
* storage: {
|
|
492
|
-
*
|
|
493
|
-
*
|
|
494
|
-
* removeItem: (key) => storageProvider.remove(key),
|
|
495
|
-
* }
|
|
533
|
+
* // A reload keeps the session (the scaffold's own default):
|
|
534
|
+
* storage: createBrowserStorageAdapter()
|
|
535
|
+
* // Only this tab's lifetime, at a narrower exposure than localStorage:
|
|
536
|
+
* storage: createBrowserStorageAdapter({ kind: 'session' })
|
|
537
|
+
* // An httpOnly cookie session instead — memory only, the stronger route:
|
|
538
|
+
* storage: 'memory'
|
|
496
539
|
* ```
|
|
497
540
|
*/
|
|
498
541
|
storage?: 'memory' | StorageAdapter
|
|
@@ -568,6 +611,16 @@ interface TokenStorage {
|
|
|
568
611
|
|
|
569
612
|
### Types
|
|
570
613
|
|
|
614
|
+
#### `BrowserStorageKind`
|
|
615
|
+
|
|
616
|
+
Which Web Storage area {@link createBrowserStorageAdapter} persists to:
|
|
617
|
+
`'local'` is `window.localStorage` (survives a reload AND the tab closing),
|
|
618
|
+
`'session'` is `window.sessionStorage` (survives a reload, dies with the tab).
|
|
619
|
+
|
|
620
|
+
```typescript
|
|
621
|
+
type BrowserStorageKind = 'local' | 'session'
|
|
622
|
+
```
|
|
623
|
+
|
|
571
624
|
#### `AuthEvent`
|
|
572
625
|
|
|
573
626
|
Auth event types.
|
|
@@ -591,6 +644,41 @@ type AuthEventListener = (event: AuthEvent) => void
|
|
|
591
644
|
|
|
592
645
|
### Functions
|
|
593
646
|
|
|
647
|
+
#### `createBrowserStorageAdapter(options)`
|
|
648
|
+
|
|
649
|
+
The auth client's `StorageAdapter` over the browser's Web Storage.
|
|
650
|
+
|
|
651
|
+
Pass it as `AuthClientConfig.storage` to keep the session across a page reload:
|
|
652
|
+
the client's default (`'memory'`) is lost on reload, and re-establishing the
|
|
653
|
+
session then needs a credential that survived — this adapter, or an httpOnly
|
|
654
|
+
session cookie the API sets (see the security note below).
|
|
655
|
+
|
|
656
|
+
```ts
|
|
657
|
+
import { createJWTAuthClient, createBrowserStorageAdapter } from '@molecule/app-auth'
|
|
658
|
+
|
|
659
|
+
const authClient = createJWTAuthClient({
|
|
660
|
+
baseURL: '/api',
|
|
661
|
+
storage: createBrowserStorageAdapter(), // a reload keeps the user signed in
|
|
662
|
+
})
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
The scaffold's `authConfig` already passes it, so a scaffolded app survives a
|
|
666
|
+
reload out of the box; each of these replaces that default:
|
|
667
|
+
|
|
668
|
+
```ts
|
|
669
|
+
storage: 'memory' // memory only: pair it with an httpOnly cookie session
|
|
670
|
+
storage: createBrowserStorageAdapter({ kind: 'session' }) // survives a reload, dies with the tab
|
|
671
|
+
storage: { getItem: (k) => …, setItem: (k, v) => …, removeItem: (k) => … } // your own
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
```typescript
|
|
675
|
+
function createBrowserStorageAdapter(options?: BrowserStorageAdapterOptions): StorageAdapter
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
- `options` — Which Web Storage area to use, or a store to use directly.
|
|
679
|
+
|
|
680
|
+
**Returns:** A synchronous `StorageAdapter` bound to that store.
|
|
681
|
+
|
|
594
682
|
#### `createJWTAuthClient(config)`
|
|
595
683
|
|
|
596
684
|
Creates a simple JWT-based auth client.
|
|
@@ -643,7 +731,7 @@ Creates a token storage implementation backed by either in-memory
|
|
|
643
731
|
storage or a custom `StorageAdapter`.
|
|
644
732
|
|
|
645
733
|
```typescript
|
|
646
|
-
function createTokenStorage(storage?: 'memory'
|
|
734
|
+
function createTokenStorage(storage?: StorageAdapter | 'memory', prefix?: string): TokenStorage
|
|
647
735
|
```
|
|
648
736
|
|
|
649
737
|
- `storage` — `'memory'` for in-memory storage (lost on refresh), or a `StorageAdapter` for persistent storage.
|
|
@@ -762,15 +850,23 @@ Peer dependencies:
|
|
|
762
850
|
- **An API with its own auth envelope keeps this client.** `requestBody` wraps the
|
|
763
851
|
login/register payload (`(kind, p) => ({ user: p })`), `mapAuthResponse` reads the
|
|
764
852
|
token and user out of the answer (`(d) => ({ accessToken: d.user.token, user: d.user })`),
|
|
765
|
-
and `authScheme: 'Token'` sends `Authorization: Token <jwt
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
853
|
+
and `authScheme: 'Token'` sends `Authorization: Token <jwt>` — both are fields of the
|
|
854
|
+
`AuthClientConfig` the client is CONSTRUCTED with
|
|
855
|
+
(`setClient(createJWTAuthClient({ authScheme: 'Token', … }))` in the auth bond), not
|
|
856
|
+
properties of a client that already exists. Do not hand-write an auth client for a spec
|
|
857
|
+
like RealWorld.
|
|
858
|
+
- **Whether a reload keeps the user signed in is `AuthClientConfig.storage`,
|
|
859
|
+
and one of the two routes must be wired.** The client's own default is
|
|
860
|
+
`'memory'`, which is lost on reload, so a session survives one only by
|
|
861
|
+
having a credential that survived: (1) `storage: createBrowserStorageAdapter()`
|
|
862
|
+
— the browser's `localStorage`, what a scaffolded app's `authConfig` passes
|
|
863
|
+
(see `@molecule/app-auth`'s `createBrowserStorageAdapter` for the trade: Web
|
|
864
|
+
Storage is script-readable, so an XSS can steal the token), or (2) an
|
|
865
|
+
httpOnly session cookie the API sets at login, which `initialize()` restores
|
|
866
|
+
through `currentUserEndpoint` (default `/users/me`) — the stronger option
|
|
867
|
+
wherever the API supports it, and what `@molecule/api-resource-user` issues.
|
|
868
|
+
Wire `initialize()` once at startup either way. Do NOT hand-roll a token
|
|
869
|
+
store beside the client for this: it is a config field.
|
|
774
870
|
- **Endpoint defaults must match your API's real routes** (`/auth/login`,
|
|
775
871
|
`/auth/register`, `/auth/refresh`, `/users/logout`, `/users/me`, …).
|
|
776
872
|
Align them via `createJWTAuthClient({ baseURL, ...endpoints })` — never by
|
|
@@ -784,6 +880,13 @@ Peer dependencies:
|
|
|
784
880
|
state being settled (`state.initialized`), or let the HTTP client do it — bond the
|
|
785
881
|
auth client through `@molecule/app-bonds-default-react`, which registers
|
|
786
882
|
`whenRestored()` as the http gate so every request waits for the restore.
|
|
883
|
+
- **Your own session store's gate must exempt its restore's own request.** This client
|
|
884
|
+
restores with `fetch`, so the gate registered over it never holds the restore. A store
|
|
885
|
+
that restores THROUGH the bonded HTTP client and registers that restore as the gate
|
|
886
|
+
(`setAuthGate(() => store.whenSettled())`) waits on itself unless the restore's request
|
|
887
|
+
passes `skipAuthGate: true` — otherwise the gate holds the very request it is waiting
|
|
888
|
+
for, and every request it holds stalls until the gate times out. See
|
|
889
|
+
`RequestConfig.skipAuthGate` in `@molecule/app-http`.
|
|
787
890
|
- Client-side auth state is UX only — the server enforces authorization on
|
|
788
891
|
every request; hiding a screen is not protection.
|
|
789
892
|
|
|
@@ -813,22 +916,27 @@ by one. A box you can't check is an integration bug to fix — not a skip:
|
|
|
813
916
|
- [ ] Visiting a protected route while logged OUT redirects to login (the
|
|
814
917
|
guard reads `isAuthenticated()`), and after authenticating you land back on
|
|
815
918
|
the originally-requested screen rather than a generic home.
|
|
816
|
-
- [ ] The session survives a FULL page reload: after login, hard-reload →
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
919
|
+
- [ ] The session survives a FULL page reload: after login, hard-reload → you
|
|
920
|
+
stay signed in (the profile/sign-out UI a signed-in visitor sees is still
|
|
921
|
+
there), and you are NOT bounced to login. Which route does it is the app's
|
|
922
|
+
`AuthClientConfig.storage`: the scaffold's `createBrowserStorageAdapter()` keeps
|
|
923
|
+
the token in the browser, an httpOnly session cookie is restored by
|
|
924
|
+
`initialize()` through `currentUserEndpoint` (default `/users/me`). If the
|
|
925
|
+
app has neither — `storage` left at `'memory'` against an API that sets no
|
|
926
|
+
cookie — this box cannot be checked, and the fix is the config, not a token
|
|
927
|
+
store written beside the client.
|
|
822
928
|
- [ ] Password reset round-trips: `requestPasswordReset({ email })` then
|
|
823
929
|
`confirmPasswordReset({ token, password })` with the emailed token, after
|
|
824
930
|
which `login()` with the NEW password succeeds and the OLD password no
|
|
825
931
|
longer works.
|
|
826
932
|
- [ ] Authorization holds: a signed-in user only ever reads/edits their OWN
|
|
827
933
|
record (`getUser()` is the caller's profile, never another user's); the
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
934
|
+
token's storage is the deliberate choice `AuthClientConfig.storage` names —
|
|
935
|
+
if it is Web Storage (the scaffold default, which a reload requires when the
|
|
936
|
+
API sets no cookie), say so in the app's own words rather than leaving a
|
|
937
|
+
second, undocumented store beside it; and an expired/invalid token fails
|
|
938
|
+
closed — the app re-authenticates (`refresh()` or `logout()`), never
|
|
939
|
+
silently serving another user's data.
|
|
832
940
|
|
|
833
941
|
## Translations
|
|
834
942
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser `StorageAdapter` for the auth client's token storage.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { StorageAdapter } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Which Web Storage area {@link createBrowserStorageAdapter} persists to:
|
|
9
|
+
* `'local'` is `window.localStorage` (survives a reload AND the tab closing),
|
|
10
|
+
* `'session'` is `window.sessionStorage` (survives a reload, dies with the tab).
|
|
11
|
+
*/
|
|
12
|
+
export type BrowserStorageKind = 'local' | 'session';
|
|
13
|
+
/** How {@link createBrowserStorageAdapter} picks the store it writes to. */
|
|
14
|
+
export interface BrowserStorageAdapterOptions {
|
|
15
|
+
/**
|
|
16
|
+
* The Web Storage area to persist to (default `'local'`).
|
|
17
|
+
*
|
|
18
|
+
* `'session'` is the narrower choice: a reload keeps the session, closing the
|
|
19
|
+
* tab ends it. Pick it when the app only has to survive navigations within one
|
|
20
|
+
* session — which is all a `page.reload()` asks for.
|
|
21
|
+
*/
|
|
22
|
+
kind?: BrowserStorageKind;
|
|
23
|
+
/**
|
|
24
|
+
* A store to use instead of resolving `window.localStorage` /
|
|
25
|
+
* `window.sessionStorage` (a test double, a namespaced wrapper, or the
|
|
26
|
+
* `Storage` object another library exposes). Anything with `getItem`/
|
|
27
|
+
* `setItem`/`removeItem` does.
|
|
28
|
+
*/
|
|
29
|
+
storage?: StorageAdapter;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The auth client's `StorageAdapter` over the browser's Web Storage.
|
|
33
|
+
*
|
|
34
|
+
* Pass it as `AuthClientConfig.storage` to keep the session across a page reload:
|
|
35
|
+
* the client's default (`'memory'`) is lost on reload, and re-establishing the
|
|
36
|
+
* session then needs a credential that survived — this adapter, or an httpOnly
|
|
37
|
+
* session cookie the API sets (see the security note below).
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { createJWTAuthClient, createBrowserStorageAdapter } from '@molecule/app-auth'
|
|
41
|
+
*
|
|
42
|
+
* const authClient = createJWTAuthClient({
|
|
43
|
+
* baseURL: '/api',
|
|
44
|
+
* storage: createBrowserStorageAdapter(), // a reload keeps the user signed in
|
|
45
|
+
* })
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* The scaffold's `authConfig` already passes it, so a scaffolded app survives a
|
|
49
|
+
* reload out of the box; each of these replaces that default:
|
|
50
|
+
*
|
|
51
|
+
* ```ts
|
|
52
|
+
* storage: 'memory' // memory only: pair it with an httpOnly cookie session
|
|
53
|
+
* storage: createBrowserStorageAdapter({ kind: 'session' }) // survives a reload, dies with the tab
|
|
54
|
+
* storage: { getItem: (k) => …, setItem: (k, v) => …, removeItem: (k) => … } // your own
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* - **The trade, stated plainly.** A bearer token in Web Storage is readable by
|
|
59
|
+
* any script on the origin, so one XSS is one token theft — an account takeover
|
|
60
|
+
* for the token's whole lifetime, and `localStorage` keeps the copy after the
|
|
61
|
+
* tab closes. This is the model the RealWorld suite's own specs write
|
|
62
|
+
* (`localStorage.setItem('jwtToken', …)` before a reload) and the reason this
|
|
63
|
+
* adapter exists.
|
|
64
|
+
* - **An httpOnly cookie session is STRONGER, and is the first choice wherever
|
|
65
|
+
* your API supports it.** Script cannot read an httpOnly cookie, so an XSS
|
|
66
|
+
* cannot exfiltrate the credential; the token stays in memory and
|
|
67
|
+
* `initialize()` restores the session through `currentUserEndpoint`
|
|
68
|
+
* (`@molecule/api-resource-user` issues exactly this cookie — that is why the
|
|
69
|
+
* client's default is `'memory'`). If the API sets one, `storage: 'memory'` is
|
|
70
|
+
* the strongest configuration. If it does not and you cannot change it, keep
|
|
71
|
+
* the token's lifetime short and rotate it on refresh.
|
|
72
|
+
* - **`kind: 'session'` narrows the window** to the tab's lifetime at the cost of
|
|
73
|
+
* losing the session in a new tab; `'local'` is the default because a reload is
|
|
74
|
+
* the requirement it exists for, and a fresh tab is the same person.
|
|
75
|
+
* - **Unavailable storage degrades to memory; it never throws.** SSR (`window`
|
|
76
|
+
* undefined), a private/blocked store and a full quota all fall back to a
|
|
77
|
+
* process-local store — so a login still succeeds and the session simply does
|
|
78
|
+
* not survive the next page load. A warning names the failure. Do not read a
|
|
79
|
+
* successful `setItem` as a guarantee of persistence; a caller that needs one
|
|
80
|
+
* must probe the store itself.
|
|
81
|
+
* - **The keys are the client's own** (`storagePrefix`, default
|
|
82
|
+
* `molecule:auth:`, plus `accessToken` / `refreshToken` / `user`); this adapter
|
|
83
|
+
* adds no prefix and stores nothing of its own.
|
|
84
|
+
*
|
|
85
|
+
* @param options - Which Web Storage area to use, or a store to use directly.
|
|
86
|
+
* @returns A synchronous `StorageAdapter` bound to that store.
|
|
87
|
+
*/
|
|
88
|
+
export declare const createBrowserStorageAdapter: (options?: BrowserStorageAdapterOptions) => StorageAdapter;
|
|
89
|
+
//# sourceMappingURL=browser-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-storage.d.ts","sourceRoot":"","sources":["../src/browser-storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,CAAA;AAEpD,4EAA4E;AAC5E,MAAM,WAAW,4BAA4B;IAC3C;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,kBAAkB,CAAA;IACzB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAeD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,eAAO,MAAM,2BAA2B,GACtC,UAAS,4BAAiC,KACzC,cA6EF,CAAA"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser `StorageAdapter` for the auth client's token storage.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { getLogger } from '@molecule/app-logger';
|
|
7
|
+
/** Best-effort logger: a missing logger bond must never break token storage. */
|
|
8
|
+
const warn = (message, error) => {
|
|
9
|
+
try {
|
|
10
|
+
const logger = getLogger('auth');
|
|
11
|
+
if (error === undefined)
|
|
12
|
+
logger.warn(message);
|
|
13
|
+
else
|
|
14
|
+
logger.warn(message, { error });
|
|
15
|
+
}
|
|
16
|
+
catch (_error) {
|
|
17
|
+
// No logger bonded (a bare unit test, an SSR boot before the app's bonds):
|
|
18
|
+
// logging is not this adapter's contract, and throwing here would take the
|
|
19
|
+
// session down with it.
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The auth client's `StorageAdapter` over the browser's Web Storage.
|
|
24
|
+
*
|
|
25
|
+
* Pass it as `AuthClientConfig.storage` to keep the session across a page reload:
|
|
26
|
+
* the client's default (`'memory'`) is lost on reload, and re-establishing the
|
|
27
|
+
* session then needs a credential that survived — this adapter, or an httpOnly
|
|
28
|
+
* session cookie the API sets (see the security note below).
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* import { createJWTAuthClient, createBrowserStorageAdapter } from '@molecule/app-auth'
|
|
32
|
+
*
|
|
33
|
+
* const authClient = createJWTAuthClient({
|
|
34
|
+
* baseURL: '/api',
|
|
35
|
+
* storage: createBrowserStorageAdapter(), // a reload keeps the user signed in
|
|
36
|
+
* })
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* The scaffold's `authConfig` already passes it, so a scaffolded app survives a
|
|
40
|
+
* reload out of the box; each of these replaces that default:
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* storage: 'memory' // memory only: pair it with an httpOnly cookie session
|
|
44
|
+
* storage: createBrowserStorageAdapter({ kind: 'session' }) // survives a reload, dies with the tab
|
|
45
|
+
* storage: { getItem: (k) => …, setItem: (k, v) => …, removeItem: (k) => … } // your own
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @remarks
|
|
49
|
+
* - **The trade, stated plainly.** A bearer token in Web Storage is readable by
|
|
50
|
+
* any script on the origin, so one XSS is one token theft — an account takeover
|
|
51
|
+
* for the token's whole lifetime, and `localStorage` keeps the copy after the
|
|
52
|
+
* tab closes. This is the model the RealWorld suite's own specs write
|
|
53
|
+
* (`localStorage.setItem('jwtToken', …)` before a reload) and the reason this
|
|
54
|
+
* adapter exists.
|
|
55
|
+
* - **An httpOnly cookie session is STRONGER, and is the first choice wherever
|
|
56
|
+
* your API supports it.** Script cannot read an httpOnly cookie, so an XSS
|
|
57
|
+
* cannot exfiltrate the credential; the token stays in memory and
|
|
58
|
+
* `initialize()` restores the session through `currentUserEndpoint`
|
|
59
|
+
* (`@molecule/api-resource-user` issues exactly this cookie — that is why the
|
|
60
|
+
* client's default is `'memory'`). If the API sets one, `storage: 'memory'` is
|
|
61
|
+
* the strongest configuration. If it does not and you cannot change it, keep
|
|
62
|
+
* the token's lifetime short and rotate it on refresh.
|
|
63
|
+
* - **`kind: 'session'` narrows the window** to the tab's lifetime at the cost of
|
|
64
|
+
* losing the session in a new tab; `'local'` is the default because a reload is
|
|
65
|
+
* the requirement it exists for, and a fresh tab is the same person.
|
|
66
|
+
* - **Unavailable storage degrades to memory; it never throws.** SSR (`window`
|
|
67
|
+
* undefined), a private/blocked store and a full quota all fall back to a
|
|
68
|
+
* process-local store — so a login still succeeds and the session simply does
|
|
69
|
+
* not survive the next page load. A warning names the failure. Do not read a
|
|
70
|
+
* successful `setItem` as a guarantee of persistence; a caller that needs one
|
|
71
|
+
* must probe the store itself.
|
|
72
|
+
* - **The keys are the client's own** (`storagePrefix`, default
|
|
73
|
+
* `molecule:auth:`, plus `accessToken` / `refreshToken` / `user`); this adapter
|
|
74
|
+
* adds no prefix and stores nothing of its own.
|
|
75
|
+
*
|
|
76
|
+
* @param options - Which Web Storage area to use, or a store to use directly.
|
|
77
|
+
* @returns A synchronous `StorageAdapter` bound to that store.
|
|
78
|
+
*/
|
|
79
|
+
export const createBrowserStorageAdapter = (options = {}) => {
|
|
80
|
+
const { kind = 'local', storage } = options;
|
|
81
|
+
// The fallback store: one Map per adapter, so an unusable Web Storage area
|
|
82
|
+
// still behaves like a store for the lifetime of the page.
|
|
83
|
+
const memory = new Map();
|
|
84
|
+
/** The store once it has answered, `null` while it is unusable (re-probed each call). */
|
|
85
|
+
let resolved;
|
|
86
|
+
/** The unusable-store warning is worth saying once, not on every token read. */
|
|
87
|
+
let warned = false;
|
|
88
|
+
const resolve = () => {
|
|
89
|
+
if (storage)
|
|
90
|
+
return storage;
|
|
91
|
+
if (resolved !== undefined && resolved !== null)
|
|
92
|
+
return resolved;
|
|
93
|
+
try {
|
|
94
|
+
const areas = globalThis;
|
|
95
|
+
const web = kind === 'session' ? areas.sessionStorage : areas.localStorage;
|
|
96
|
+
if (web) {
|
|
97
|
+
// A store can be PRESENT and still unusable (a blocked third-party
|
|
98
|
+
// context, a private mode): touching it throws, so probe before trusting it.
|
|
99
|
+
const probe = '__molecule_auth_probe__';
|
|
100
|
+
web.setItem(probe, probe);
|
|
101
|
+
web.removeItem(probe);
|
|
102
|
+
resolved = web;
|
|
103
|
+
return web;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
if (!warned) {
|
|
108
|
+
warned = true;
|
|
109
|
+
warn(`The ${kind} Web Storage area is not usable; keeping auth tokens in memory`, error);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Not cached: a store that appears later (the app booting before its DOM is
|
|
113
|
+
// ready) is still picked up by the next call.
|
|
114
|
+
return null;
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
getItem: (key) => {
|
|
118
|
+
const store = resolve();
|
|
119
|
+
if (!store)
|
|
120
|
+
return memory.get(key) ?? null;
|
|
121
|
+
try {
|
|
122
|
+
// A write that fell back to memory (a full or blocked store) is still
|
|
123
|
+
// this session's value: the store simply never received it.
|
|
124
|
+
return store.getItem(key) ?? memory.get(key) ?? null;
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
warn('Reading a stored auth value failed; falling back to memory', error);
|
|
128
|
+
return memory.get(key) ?? null;
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
setItem: (key, value) => {
|
|
132
|
+
const store = resolve();
|
|
133
|
+
if (!store) {
|
|
134
|
+
memory.set(key, value);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
store.setItem(key, value);
|
|
139
|
+
memory.delete(key);
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
// A quota-full or blocked store must not fail a login: keep the value for
|
|
143
|
+
// this page's lifetime and say so. The session is lost on reload, which is
|
|
144
|
+
// the state the app was in before this adapter existed.
|
|
145
|
+
warn('Storing an auth value failed; keeping it in memory for this page', error);
|
|
146
|
+
memory.set(key, value);
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
removeItem: (key) => {
|
|
150
|
+
memory.delete(key);
|
|
151
|
+
const store = resolve();
|
|
152
|
+
if (!store)
|
|
153
|
+
return;
|
|
154
|
+
try {
|
|
155
|
+
store.removeItem(key);
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
warn('Clearing a stored auth value failed', error);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
//# sourceMappingURL=browser-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-storage.js","sourceRoot":"","sources":["../src/browser-storage.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,15 +12,23 @@
|
|
|
12
12
|
* - **An API with its own auth envelope keeps this client.** `requestBody` wraps the
|
|
13
13
|
* login/register payload (`(kind, p) => ({ user: p })`), `mapAuthResponse` reads the
|
|
14
14
|
* token and user out of the answer (`(d) => ({ accessToken: d.user.token, user: d.user })`),
|
|
15
|
-
* and `authScheme: 'Token'` sends `Authorization: Token <jwt
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
15
|
+
* and `authScheme: 'Token'` sends `Authorization: Token <jwt>` — both are fields of the
|
|
16
|
+
* `AuthClientConfig` the client is CONSTRUCTED with
|
|
17
|
+
* (`setClient(createJWTAuthClient({ authScheme: 'Token', … }))` in the auth bond), not
|
|
18
|
+
* properties of a client that already exists. Do not hand-write an auth client for a spec
|
|
19
|
+
* like RealWorld.
|
|
20
|
+
* - **Whether a reload keeps the user signed in is `AuthClientConfig.storage`,
|
|
21
|
+
* and one of the two routes must be wired.** The client's own default is
|
|
22
|
+
* `'memory'`, which is lost on reload, so a session survives one only by
|
|
23
|
+
* having a credential that survived: (1) `storage: createBrowserStorageAdapter()`
|
|
24
|
+
* — the browser's `localStorage`, what a scaffolded app's `authConfig` passes
|
|
25
|
+
* (see `@molecule/app-auth`'s `createBrowserStorageAdapter` for the trade: Web
|
|
26
|
+
* Storage is script-readable, so an XSS can steal the token), or (2) an
|
|
27
|
+
* httpOnly session cookie the API sets at login, which `initialize()` restores
|
|
28
|
+
* through `currentUserEndpoint` (default `/users/me`) — the stronger option
|
|
29
|
+
* wherever the API supports it, and what `@molecule/api-resource-user` issues.
|
|
30
|
+
* Wire `initialize()` once at startup either way. Do NOT hand-roll a token
|
|
31
|
+
* store beside the client for this: it is a config field.
|
|
24
32
|
* - **Endpoint defaults must match your API's real routes** (`/auth/login`,
|
|
25
33
|
* `/auth/register`, `/auth/refresh`, `/users/logout`, `/users/me`, …).
|
|
26
34
|
* Align them via `createJWTAuthClient({ baseURL, ...endpoints })` — never by
|
|
@@ -34,6 +42,13 @@
|
|
|
34
42
|
* state being settled (`state.initialized`), or let the HTTP client do it — bond the
|
|
35
43
|
* auth client through `@molecule/app-bonds-default-react`, which registers
|
|
36
44
|
* `whenRestored()` as the http gate so every request waits for the restore.
|
|
45
|
+
* - **Your own session store's gate must exempt its restore's own request.** This client
|
|
46
|
+
* restores with `fetch`, so the gate registered over it never holds the restore. A store
|
|
47
|
+
* that restores THROUGH the bonded HTTP client and registers that restore as the gate
|
|
48
|
+
* (`setAuthGate(() => store.whenSettled())`) waits on itself unless the restore's request
|
|
49
|
+
* passes `skipAuthGate: true` — otherwise the gate holds the very request it is waiting
|
|
50
|
+
* for, and every request it holds stalls until the gate times out. See
|
|
51
|
+
* `RequestConfig.skipAuthGate` in `@molecule/app-http`.
|
|
37
52
|
* - Client-side auth state is UX only — the server enforces authorization on
|
|
38
53
|
* every request; hiding a screen is not protection.
|
|
39
54
|
*
|
|
@@ -75,25 +90,31 @@
|
|
|
75
90
|
* - [ ] Visiting a protected route while logged OUT redirects to login (the
|
|
76
91
|
* guard reads `isAuthenticated()`), and after authenticating you land back on
|
|
77
92
|
* the originally-requested screen rather than a generic home.
|
|
78
|
-
* - [ ] The session survives a FULL page reload: after login, hard-reload →
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
93
|
+
* - [ ] The session survives a FULL page reload: after login, hard-reload → you
|
|
94
|
+
* stay signed in (the profile/sign-out UI a signed-in visitor sees is still
|
|
95
|
+
* there), and you are NOT bounced to login. Which route does it is the app's
|
|
96
|
+
* `AuthClientConfig.storage`: the scaffold's `createBrowserStorageAdapter()` keeps
|
|
97
|
+
* the token in the browser, an httpOnly session cookie is restored by
|
|
98
|
+
* `initialize()` through `currentUserEndpoint` (default `/users/me`). If the
|
|
99
|
+
* app has neither — `storage` left at `'memory'` against an API that sets no
|
|
100
|
+
* cookie — this box cannot be checked, and the fix is the config, not a token
|
|
101
|
+
* store written beside the client.
|
|
84
102
|
* - [ ] Password reset round-trips: `requestPasswordReset({ email })` then
|
|
85
103
|
* `confirmPasswordReset({ token, password })` with the emailed token, after
|
|
86
104
|
* which `login()` with the NEW password succeeds and the OLD password no
|
|
87
105
|
* longer works.
|
|
88
106
|
* - [ ] Authorization holds: a signed-in user only ever reads/edits their OWN
|
|
89
107
|
* record (`getUser()` is the caller's profile, never another user's); the
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
108
|
+
* token's storage is the deliberate choice `AuthClientConfig.storage` names —
|
|
109
|
+
* if it is Web Storage (the scaffold default, which a reload requires when the
|
|
110
|
+
* API sets no cookie), say so in the app's own words rather than leaving a
|
|
111
|
+
* second, undocumented store beside it; and an expired/invalid token fails
|
|
112
|
+
* closed — the app re-authenticates (`refresh()` or `logout()`), never
|
|
113
|
+
* silently serving another user's data.
|
|
94
114
|
*
|
|
95
115
|
* @module
|
|
96
116
|
*/
|
|
117
|
+
export * from './browser-storage.js';
|
|
97
118
|
export * from './client.js';
|
|
98
119
|
export * from './provider.js';
|
|
99
120
|
export * from './token.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmHG;AAEH,cAAc,sBAAsB,CAAA;AACpC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -12,15 +12,23 @@
|
|
|
12
12
|
* - **An API with its own auth envelope keeps this client.** `requestBody` wraps the
|
|
13
13
|
* login/register payload (`(kind, p) => ({ user: p })`), `mapAuthResponse` reads the
|
|
14
14
|
* token and user out of the answer (`(d) => ({ accessToken: d.user.token, user: d.user })`),
|
|
15
|
-
* and `authScheme: 'Token'` sends `Authorization: Token <jwt
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
15
|
+
* and `authScheme: 'Token'` sends `Authorization: Token <jwt>` — both are fields of the
|
|
16
|
+
* `AuthClientConfig` the client is CONSTRUCTED with
|
|
17
|
+
* (`setClient(createJWTAuthClient({ authScheme: 'Token', … }))` in the auth bond), not
|
|
18
|
+
* properties of a client that already exists. Do not hand-write an auth client for a spec
|
|
19
|
+
* like RealWorld.
|
|
20
|
+
* - **Whether a reload keeps the user signed in is `AuthClientConfig.storage`,
|
|
21
|
+
* and one of the two routes must be wired.** The client's own default is
|
|
22
|
+
* `'memory'`, which is lost on reload, so a session survives one only by
|
|
23
|
+
* having a credential that survived: (1) `storage: createBrowserStorageAdapter()`
|
|
24
|
+
* — the browser's `localStorage`, what a scaffolded app's `authConfig` passes
|
|
25
|
+
* (see `@molecule/app-auth`'s `createBrowserStorageAdapter` for the trade: Web
|
|
26
|
+
* Storage is script-readable, so an XSS can steal the token), or (2) an
|
|
27
|
+
* httpOnly session cookie the API sets at login, which `initialize()` restores
|
|
28
|
+
* through `currentUserEndpoint` (default `/users/me`) — the stronger option
|
|
29
|
+
* wherever the API supports it, and what `@molecule/api-resource-user` issues.
|
|
30
|
+
* Wire `initialize()` once at startup either way. Do NOT hand-roll a token
|
|
31
|
+
* store beside the client for this: it is a config field.
|
|
24
32
|
* - **Endpoint defaults must match your API's real routes** (`/auth/login`,
|
|
25
33
|
* `/auth/register`, `/auth/refresh`, `/users/logout`, `/users/me`, …).
|
|
26
34
|
* Align them via `createJWTAuthClient({ baseURL, ...endpoints })` — never by
|
|
@@ -34,6 +42,13 @@
|
|
|
34
42
|
* state being settled (`state.initialized`), or let the HTTP client do it — bond the
|
|
35
43
|
* auth client through `@molecule/app-bonds-default-react`, which registers
|
|
36
44
|
* `whenRestored()` as the http gate so every request waits for the restore.
|
|
45
|
+
* - **Your own session store's gate must exempt its restore's own request.** This client
|
|
46
|
+
* restores with `fetch`, so the gate registered over it never holds the restore. A store
|
|
47
|
+
* that restores THROUGH the bonded HTTP client and registers that restore as the gate
|
|
48
|
+
* (`setAuthGate(() => store.whenSettled())`) waits on itself unless the restore's request
|
|
49
|
+
* passes `skipAuthGate: true` — otherwise the gate holds the very request it is waiting
|
|
50
|
+
* for, and every request it holds stalls until the gate times out. See
|
|
51
|
+
* `RequestConfig.skipAuthGate` in `@molecule/app-http`.
|
|
37
52
|
* - Client-side auth state is UX only — the server enforces authorization on
|
|
38
53
|
* every request; hiding a screen is not protection.
|
|
39
54
|
*
|
|
@@ -75,25 +90,31 @@
|
|
|
75
90
|
* - [ ] Visiting a protected route while logged OUT redirects to login (the
|
|
76
91
|
* guard reads `isAuthenticated()`), and after authenticating you land back on
|
|
77
92
|
* the originally-requested screen rather than a generic home.
|
|
78
|
-
* - [ ] The session survives a FULL page reload: after login, hard-reload →
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
93
|
+
* - [ ] The session survives a FULL page reload: after login, hard-reload → you
|
|
94
|
+
* stay signed in (the profile/sign-out UI a signed-in visitor sees is still
|
|
95
|
+
* there), and you are NOT bounced to login. Which route does it is the app's
|
|
96
|
+
* `AuthClientConfig.storage`: the scaffold's `createBrowserStorageAdapter()` keeps
|
|
97
|
+
* the token in the browser, an httpOnly session cookie is restored by
|
|
98
|
+
* `initialize()` through `currentUserEndpoint` (default `/users/me`). If the
|
|
99
|
+
* app has neither — `storage` left at `'memory'` against an API that sets no
|
|
100
|
+
* cookie — this box cannot be checked, and the fix is the config, not a token
|
|
101
|
+
* store written beside the client.
|
|
84
102
|
* - [ ] Password reset round-trips: `requestPasswordReset({ email })` then
|
|
85
103
|
* `confirmPasswordReset({ token, password })` with the emailed token, after
|
|
86
104
|
* which `login()` with the NEW password succeeds and the OLD password no
|
|
87
105
|
* longer works.
|
|
88
106
|
* - [ ] Authorization holds: a signed-in user only ever reads/edits their OWN
|
|
89
107
|
* record (`getUser()` is the caller's profile, never another user's); the
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
108
|
+
* token's storage is the deliberate choice `AuthClientConfig.storage` names —
|
|
109
|
+
* if it is Web Storage (the scaffold default, which a reload requires when the
|
|
110
|
+
* API sets no cookie), say so in the app's own words rather than leaving a
|
|
111
|
+
* second, undocumented store beside it; and an expired/invalid token fails
|
|
112
|
+
* closed — the app re-authenticates (`refresh()` or `logout()`), never
|
|
113
|
+
* silently serving another user's data.
|
|
94
114
|
*
|
|
95
115
|
* @module
|
|
96
116
|
*/
|
|
117
|
+
export * from './browser-storage.js';
|
|
97
118
|
export * from './client.js';
|
|
98
119
|
export * from './provider.js';
|
|
99
120
|
export * from './token.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmHG;AAEH,cAAc,sBAAsB,CAAA;AACpC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
|
package/dist/token.d.ts
CHANGED
|
@@ -17,17 +17,12 @@ import type { StorageAdapter, TokenStorage } from './types.js';
|
|
|
17
17
|
*
|
|
18
18
|
* @example
|
|
19
19
|
* ```typescript
|
|
20
|
-
* // In-memory storage (default)
|
|
20
|
+
* // In-memory storage (the client's default)
|
|
21
21
|
* const storage = createTokenStorage('memory')
|
|
22
22
|
*
|
|
23
|
-
* //
|
|
24
|
-
* import {
|
|
25
|
-
* const
|
|
26
|
-
* const storage = createTokenStorage({
|
|
27
|
-
* getItem: (key) => provider.get(key),
|
|
28
|
-
* setItem: (key, value) => provider.set(key, value),
|
|
29
|
-
* removeItem: (key) => provider.remove(key),
|
|
30
|
-
* })
|
|
23
|
+
* // The browser's persistent storage — a reload keeps the session
|
|
24
|
+
* import { createBrowserStorageAdapter } from '@molecule/app-auth'
|
|
25
|
+
* const storage = createTokenStorage(createBrowserStorageAdapter())
|
|
31
26
|
* ```
|
|
32
27
|
*/
|
|
33
28
|
export declare const createTokenStorage: (storage?: "memory" | StorageAdapter, prefix?: string) => TokenStorage;
|
package/dist/token.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAe,MAAM,YAAY,CAAA;AAE3E
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAe,MAAM,YAAY,CAAA;AAE3E;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAS,QAAQ,GAAG,cAAyB,EAC7C,SAAQ,MAAyB,KAChC,YAoDF,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,MAAM,KAAG,CAAC,GAAG,IAWzE,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,EAAE,gBAAe,MAAU,KAAG,OAMzE,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,IAI3D,CAAA"}
|
package/dist/token.js
CHANGED
|
@@ -16,17 +16,12 @@
|
|
|
16
16
|
*
|
|
17
17
|
* @example
|
|
18
18
|
* ```typescript
|
|
19
|
-
* // In-memory storage (default)
|
|
19
|
+
* // In-memory storage (the client's default)
|
|
20
20
|
* const storage = createTokenStorage('memory')
|
|
21
21
|
*
|
|
22
|
-
* //
|
|
23
|
-
* import {
|
|
24
|
-
* const
|
|
25
|
-
* const storage = createTokenStorage({
|
|
26
|
-
* getItem: (key) => provider.get(key),
|
|
27
|
-
* setItem: (key, value) => provider.set(key, value),
|
|
28
|
-
* removeItem: (key) => provider.remove(key),
|
|
29
|
-
* })
|
|
22
|
+
* // The browser's persistent storage — a reload keeps the session
|
|
23
|
+
* import { createBrowserStorageAdapter } from '@molecule/app-auth'
|
|
24
|
+
* const storage = createTokenStorage(createBrowserStorageAdapter())
|
|
30
25
|
* ```
|
|
31
26
|
*/
|
|
32
27
|
export const createTokenStorage = (storage = 'memory', prefix = 'molecule:auth:') => {
|
package/dist/token.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -263,6 +263,12 @@ export interface AuthClient<T = UserProfile> {
|
|
|
263
263
|
*
|
|
264
264
|
* Optional: a provider that restores no session has nothing to wait for. Without it, an
|
|
265
265
|
* HTTP client bonded to that provider sends first-paint requests unauthenticated.
|
|
266
|
+
*
|
|
267
|
+
* A provider whose restore sends a request THROUGH the gated HTTP client must send that
|
|
268
|
+
* request with `skipAuthGate: true` (`RequestConfig` in `@molecule/app-http`): the gate
|
|
269
|
+
* waits on this promise, so holding the restore's own request makes the gate wait on
|
|
270
|
+
* itself and stalls every request it holds until it times out. `createJWTAuthClient`'s
|
|
271
|
+
* restore does not need it — it uses `fetch`, not the bonded client.
|
|
266
272
|
*/
|
|
267
273
|
whenRestored?(): Promise<void>;
|
|
268
274
|
/**
|
|
@@ -326,10 +332,10 @@ export interface AuthClientConfig {
|
|
|
326
332
|
profileEndpoint?: string;
|
|
327
333
|
/**
|
|
328
334
|
* Current-user endpoint for session restore (default `/users/me`). Called by
|
|
329
|
-
* `initialize()` with credentials to re-establish the session
|
|
330
|
-
*
|
|
331
|
-
*
|
|
332
|
-
*
|
|
335
|
+
* `initialize()` with credentials to re-establish the session after a full page
|
|
336
|
+
* load when the token did not survive the reload itself — i.e. when `storage` is
|
|
337
|
+
* `'memory'` and the API sets an httpOnly session cookie. Must return the user
|
|
338
|
+
* (as `user` or `props`).
|
|
333
339
|
*/
|
|
334
340
|
currentUserEndpoint?: string;
|
|
335
341
|
/**
|
|
@@ -360,23 +366,36 @@ export interface AuthClientConfig {
|
|
|
360
366
|
*/
|
|
361
367
|
mapAuthResponse?: (data: unknown) => AuthResult<UserProfile>;
|
|
362
368
|
/**
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
369
|
+
* Where the access/refresh token and the cached user are kept — the field that
|
|
370
|
+
* decides whether a page reload keeps the user signed in.
|
|
371
|
+
*
|
|
372
|
+
* - `'memory'` (the client's default): a process-local store, lost on reload.
|
|
373
|
+
* Correct when the API sets an httpOnly session cookie, which `initialize()`
|
|
374
|
+
* then restores through {@link AuthClientConfig.currentUserEndpoint} — the
|
|
375
|
+
* strongest configuration, because no script can read the cookie.
|
|
376
|
+
* - a `StorageAdapter`: the token survives the reload itself. The browser
|
|
377
|
+
* adapter is `createBrowserStorageAdapter()` (from `@molecule/app-auth`), and
|
|
378
|
+
* the scaffold's generated auth bond (`src/bonds/auth-default.ts`) passes it;
|
|
379
|
+
* `src/config.ts` leaves `storage` out on purpose. A bearer token in Web
|
|
380
|
+
* Storage is readable by any script on the origin, so an XSS can steal it; see
|
|
381
|
+
* that function's `@remarks` for the trade and for the cookie alternative.
|
|
382
|
+
*
|
|
383
|
+
* Any adapter with `getItem`/`setItem`/`removeItem` works — the methods are
|
|
384
|
+
* SYNCHRONOUS, so the async `@molecule/app-storage` provider
|
|
385
|
+
* (`getProvider()`, whose `get()` returns a Promise) is NOT one: wrap the
|
|
386
|
+
* `Storage` object it was built on (`createBrowserStorageAdapter({ storage })`),
|
|
387
|
+
* or store a different way.
|
|
366
388
|
*
|
|
367
389
|
* @example
|
|
368
390
|
* ```typescript
|
|
369
|
-
*
|
|
370
|
-
* storage: 'memory'
|
|
391
|
+
* import { createBrowserStorageAdapter } from '@molecule/app-auth'
|
|
371
392
|
*
|
|
372
|
-
* //
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* storage: {
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
* removeItem: (key) => storageProvider.remove(key),
|
|
379
|
-
* }
|
|
393
|
+
* // A reload keeps the session (the scaffold's own default):
|
|
394
|
+
* storage: createBrowserStorageAdapter()
|
|
395
|
+
* // Only this tab's lifetime, at a narrower exposure than localStorage:
|
|
396
|
+
* storage: createBrowserStorageAdapter({ kind: 'session' })
|
|
397
|
+
* // An httpOnly cookie session instead — memory only, the stronger route:
|
|
398
|
+
* storage: 'memory'
|
|
380
399
|
* ```
|
|
381
400
|
*/
|
|
382
401
|
storage?: 'memory' | StorageAdapter;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|