@molecule/app-auth 3.0.2 → 3.2.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 +210 -101
- package/dist/browser-storage.d.ts +5 -4
- package/dist/browser-storage.d.ts.map +1 -1
- package/dist/browser-storage.js +5 -4
- package/dist/browser-storage.js.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +718 -348
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +86 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +86 -30
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +121 -31
- package/dist/types.d.ts.map +1 -1
- package/dist/utilities.d.ts +1 -1
- package/dist/utilities.js +1 -1
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@ 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-
|
|
6
|
+
Generated: 2026-11-02T07:28:20.788Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/app-auth
|
|
@@ -17,19 +17,54 @@ client; `setClient`/`getClient` bond it; `login`/`logout`/`register`/
|
|
|
17
17
|
bindings (e.g. `AuthProvider`/`useAuth` in `@molecule/app-react`) wrap the
|
|
18
18
|
same client.
|
|
19
19
|
|
|
20
|
-
**
|
|
21
|
-
|
|
20
|
+
**What this client already handles**
|
|
21
|
+
|
|
22
|
+
- `getAccessToken()` returns a stored token immediately, even while restore is pending.
|
|
23
|
+
- Only 401/403 ends a session; network and 5xx restore failures retain it.
|
|
24
|
+
- `tokenKey`/`storagePrefix`, `authScheme`, `mapAuthResponse`,
|
|
25
|
+
`currentUserEndpoint`, and `profileEndpoint`/`profileUpdateMethod` adapt the API.
|
|
26
|
+
- `logout()` clears the local session even if revocation fails; `refresh()` and
|
|
27
|
+
optional auto-refresh use a stored refresh token.
|
|
28
|
+
- `AuthProvider` renders children immediately and gates nothing; only a route guard
|
|
29
|
+
chooses to wait for `status === 'loading'`.
|
|
30
|
+
|
|
31
|
+
A token nested in the user, a custom key and current-user route, a PUT update,
|
|
32
|
+
and `Authorization: Token <jwt>` need configuration, not another session layer:
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { createJWTAuthClient } from '@molecule/app-auth'
|
|
36
|
+
const client = createJWTAuthClient({
|
|
37
|
+
tokenKey: 'app.jwt',
|
|
38
|
+
authScheme: 'Token',
|
|
39
|
+
currentUserEndpoint: '/user',
|
|
40
|
+
profileEndpoint: '/user',
|
|
41
|
+
profileUpdateMethod: 'PUT',
|
|
42
|
+
mapAuthResponse: (data) => {
|
|
43
|
+
const { token, ...user } = (data as { user: { token: string; id: string } }).user
|
|
44
|
+
return { accessToken: token, user }
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**In a scaffolded app, keep the generated auth bond.** It already creates and
|
|
50
|
+
bonds one client from `authConfig`; adapt that config and read the session through
|
|
51
|
+
`MoleculeProvider`/`useAuth()` instead of adding another session layer. In an existing
|
|
52
|
+
app without that bond, create the client once at startup with
|
|
22
53
|
`setClient(createJWTAuthClient({ baseURL, authScheme: 'Token', storage:
|
|
23
54
|
createBrowserStorageAdapter() }))`, or `createDefaultAuthClient(authConfig)`
|
|
24
|
-
from `@molecule/app-bonds-default-react`
|
|
25
|
-
`whenRestored()` as the
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
55
|
+
from `@molecule/app-bonds-default-react`, then call `initialize()`. The bond's
|
|
56
|
+
HTTP-sync variants also register `whenRestored()` as the request gate.
|
|
57
|
+
|
|
58
|
+
**`initialize()` restores a cached token AND user BEFORE the first render.**
|
|
59
|
+
That restore is synchronous and costs no request. Cookie-only and token-only
|
|
60
|
+
restoration need an asynchronous current-user request. An HttpOnly
|
|
61
|
+
session cookie restores through `currentUserEndpoint` (default `/users/me`).
|
|
62
|
+
The default `cookieRestore: 'hint'` requires a readable `mol_auth=1` cookie
|
|
63
|
+
set by the API alongside the HttpOnly cookie. For an external cookie API
|
|
64
|
+
without that convention, configure `storage: 'memory'`,
|
|
65
|
+
`cookieRestore: 'always'`, and its `currentUserEndpoint`. Keep the HTTP
|
|
66
|
+
client's `withCredentials: true`. This explicit policy also probes anonymous
|
|
67
|
+
loads; a local sign-out suppresses further probes until sign-in succeeds. With only an access token,
|
|
33
68
|
it loads and maps the profile from that endpoint once before deciding the
|
|
34
69
|
session: 401/403 clears the token; network/5xx failures retain it as
|
|
35
70
|
`unavailable`. `AuthClientConfig.storage` is
|
|
@@ -50,8 +85,8 @@ then stays on its loading branch).
|
|
|
50
85
|
**Never fetch viewer-dependent data before the restore settles.** A
|
|
51
86
|
component effect that runs on mount fires while `initialize()` is still
|
|
52
87
|
restoring, so its request leaves without the `Authorization` header and the
|
|
53
|
-
server answers for an anonymous viewer —
|
|
54
|
-
|
|
88
|
+
server answers for an anonymous viewer — saved preferences appear unset and
|
|
89
|
+
account-specific controls show anonymous defaults. On localhost the restore usually wins this race;
|
|
55
90
|
over the network it does not, so the bug appears only on the deployed URL.
|
|
56
91
|
Gate the fetch on the auth state being settled (`state.initialized`), or let
|
|
57
92
|
the HTTP client do it: `@molecule/app-bonds-default-react` registers
|
|
@@ -71,8 +106,7 @@ mirrors the token into the bonded client.
|
|
|
71
106
|
`initialize()` sets that state synchronously, before any request, and every
|
|
72
107
|
verification settles behind that render. Never hold the first paint on
|
|
73
108
|
`validateSession()` or a `/me` request of your own — a protected page then pays
|
|
74
|
-
an API round trip on every navigation
|
|
75
|
-
spec put four tests at 15.0–15.9 s of a 15 s budget, and two timed out). Route
|
|
109
|
+
an API round trip on every navigation. Route
|
|
76
110
|
guards read this same `status`: wait only while it is `'loading'` — that
|
|
77
111
|
status means "no decision yet", so an auth request in flight
|
|
78
112
|
(`state.loading`) keeps the decided status and does not unmount a
|
|
@@ -86,8 +120,9 @@ KEEPS the token and the user (`'unavailable'`, retryable; the 404 error names
|
|
|
86
120
|
plus its own listener set is a second session store, and it drifts from the
|
|
87
121
|
client's.
|
|
88
122
|
|
|
89
|
-
**Only a 401/403
|
|
90
|
-
|
|
123
|
+
**Only a server 401/403 rejects a credential; no response never does.** Explicit
|
|
124
|
+
sign-out and an application restore predicate can also end the local session.
|
|
125
|
+
Every server-failure path that clears the stored session (`validateSession`, the cookie restore, the initial
|
|
91
126
|
refresh, the background refresh timer) keys on the server REJECTING the
|
|
92
127
|
credential. An aborted request, a dropped connection, or a 5xx arrives with no
|
|
93
128
|
HTTP status (or `status: 0` from `@molecule/app-http`) and says nothing about the
|
|
@@ -105,10 +140,12 @@ whole parsed body is preserved, nested maps and arrays included, not just the
|
|
|
105
140
|
`error`/`message` the message is built from, so a login form can render the
|
|
106
141
|
API's own validation payload (`{ errors: { credentials: ['is invalid'] } }`)
|
|
107
142
|
instead of re-implementing the call. A body that is not JSON arrives as `{}`;
|
|
108
|
-
the key, message, fallback and rejection are unchanged.
|
|
143
|
+
the key, message, fallback and rejection are unchanged. That same rejection also
|
|
144
|
+
satisfies `isHttpError(err)` from `@molecule/app-http`, with
|
|
145
|
+
`response.data === body`, so an app-http error reader works without changing the
|
|
146
|
+
`I18nError` contract.
|
|
109
147
|
|
|
110
|
-
**`autoRefresh` does nothing without a refresh token
|
|
111
|
-
user out.** The client schedules a refresh only when `refresh()` could actually
|
|
148
|
+
**`autoRefresh` does nothing without a refresh token.** The client schedules a refresh only when `refresh()` could actually
|
|
112
149
|
succeed, i.e. when a refresh token is stored. An API that issues none (the
|
|
113
150
|
`@molecule/api-resource-user` model: login/register return `{ accessToken,
|
|
114
151
|
user }` and the durable session is an httpOnly cookie the SERVER refreshes)
|
|
@@ -123,7 +160,8 @@ user, `setSession({ accessToken, user })` stores both and flips the client to
|
|
|
123
160
|
(a form's own sign-in code wrote the token and the user with `setAccessToken`/`setUser`,
|
|
124
161
|
which change their field only — the UI stays signed out and the browser assertions that
|
|
125
162
|
expect it time out). `setAccessToken()` and `setUser()` are field setters, not a
|
|
126
|
-
sign-in: neither
|
|
163
|
+
sign-in: neither establishes an authenticated session. On a signed-in client,
|
|
164
|
+
`setUser(null)` instead ends the local session and clears its stored credentials.
|
|
127
165
|
|
|
128
166
|
**A custom user profile is typed once and used everywhere: `AuthClientConfig<MyUser>`,
|
|
129
167
|
`createJWTAuthClient<MyUser>` and `useAuth<MyUser>()`.** The config's generic makes
|
|
@@ -257,8 +295,8 @@ submission, the saved baseline and cache propagation. Use that composition
|
|
|
257
295
|
for editable account forms instead of resetting every field on `user` changes.
|
|
258
296
|
|
|
259
297
|
**A token another tool reads at its own key is a CONFIG field, not a mirror.**
|
|
260
|
-
An e2e suite or host page that expects `localStorage.
|
|
261
|
-
|
|
298
|
+
An e2e suite or host page that expects `localStorage.getItem('app.jwt')` is
|
|
299
|
+
satisfied by `tokenKey: 'app.jwt'` — in a browser the client's
|
|
262
300
|
storage default is already `createBrowserStorageAdapter()`, so with an explicit
|
|
263
301
|
`'memory'` store you must also pass
|
|
264
302
|
`storage: createBrowserStorageAdapter()`. Writing the token into that key from a
|
|
@@ -294,35 +332,35 @@ await login({ email, password })
|
|
|
294
332
|
if (isAuthenticated()) console.log(getUser()?.email)
|
|
295
333
|
```
|
|
296
334
|
|
|
297
|
-
An API that wraps the payload and registers extra fields
|
|
335
|
+
An API that wraps the payload and registers extra fields: type those
|
|
298
336
|
fields with the factory's second generic, and `requestBody` receives exactly what
|
|
299
337
|
the form passed — `{ user: { username, email, password } }` goes out as-is.
|
|
300
338
|
|
|
301
339
|
```typescript
|
|
302
340
|
import { createJWTAuthClient } from '@molecule/app-auth'
|
|
303
341
|
|
|
304
|
-
//
|
|
342
|
+
// This account API's user has no `id`. Name the shape the wire actually sends; the
|
|
305
343
|
// client reads no field of it, so nothing has to be invented for a base profile.
|
|
306
|
-
interface
|
|
344
|
+
interface AccountProfile {
|
|
307
345
|
username: string
|
|
308
346
|
email: string
|
|
309
347
|
bio: string
|
|
310
348
|
image: string
|
|
311
349
|
}
|
|
312
350
|
|
|
313
|
-
const
|
|
351
|
+
const accountAuth = createJWTAuthClient<AccountProfile, { username: string }>({
|
|
314
352
|
baseURL: '/api',
|
|
315
353
|
authScheme: 'Token',
|
|
316
354
|
requestBody: (_kind, payload) => ({ user: payload }),
|
|
317
355
|
mapAuthResponse: (data) => {
|
|
318
|
-
const { user: wire } = data as { user: { token: string } &
|
|
356
|
+
const { user: wire } = data as { user: { token: string } & AccountProfile }
|
|
319
357
|
// Keep every wire field; the bearer stays out of the cached profile.
|
|
320
358
|
const { token, ...profile } = wire
|
|
321
359
|
return { accessToken: token, user: profile }
|
|
322
360
|
},
|
|
323
361
|
})
|
|
324
362
|
|
|
325
|
-
await
|
|
363
|
+
await accountAuth.register({ username: 'alice', email: 'alice@example.com', password: 's3cret' })
|
|
326
364
|
```
|
|
327
365
|
|
|
328
366
|
## Type
|
|
@@ -332,7 +370,7 @@ await realWorldAuth.register({ username: 'alice', email: 'alice@example.com', pa
|
|
|
332
370
|
## Installation
|
|
333
371
|
|
|
334
372
|
```bash
|
|
335
|
-
npm install @molecule/app-auth @molecule/app-bond @molecule/app-i18n @molecule/app-logger
|
|
373
|
+
npm install @molecule/app-auth @molecule/app-bond @molecule/app-http @molecule/app-i18n @molecule/app-logger
|
|
336
374
|
```
|
|
337
375
|
|
|
338
376
|
## API
|
|
@@ -468,6 +506,21 @@ interface AuthResult<T = UserProfile> {
|
|
|
468
506
|
}
|
|
469
507
|
```
|
|
470
508
|
|
|
509
|
+
#### `AuthChallenge`
|
|
510
|
+
|
|
511
|
+
A 206 challenge: control fields survive, but no authenticated session exists.
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
interface AuthChallenge {
|
|
515
|
+
twoFactorRequired: true
|
|
516
|
+
user?: never
|
|
517
|
+
accessToken?: never
|
|
518
|
+
refreshToken?: never
|
|
519
|
+
expiresAt?: never
|
|
520
|
+
[controlField: string]: unknown
|
|
521
|
+
}
|
|
522
|
+
```
|
|
523
|
+
|
|
471
524
|
#### `PasswordResetRequest`
|
|
472
525
|
|
|
473
526
|
Password reset request data.
|
|
@@ -507,7 +560,10 @@ Reactive authentication state snapshot (initialized, authenticated, user, loadin
|
|
|
507
560
|
interface AuthState<T = UserProfile> {
|
|
508
561
|
/**
|
|
509
562
|
* The session's state as one value — render from this instead of combining
|
|
510
|
-
* `initialized`/`authenticated`/`loading`.
|
|
563
|
+
* `initialized`/`authenticated`/`loading`. `'loading'` is undecided, so wait
|
|
564
|
+
* and redirect only on `'unauthenticated'`; `'unavailable'` keeps the candidate
|
|
565
|
+
* for retry and can have a null profile. A restore failure other than 401/403
|
|
566
|
+
* never signs out. See {@link AuthStatus}.
|
|
511
567
|
*/
|
|
512
568
|
status: AuthStatus
|
|
513
569
|
|
|
@@ -517,12 +573,15 @@ interface AuthState<T = UserProfile> {
|
|
|
517
573
|
initialized: boolean
|
|
518
574
|
|
|
519
575
|
/**
|
|
520
|
-
* Whether the
|
|
576
|
+
* Whether the client has an authenticated session. This is not a server
|
|
577
|
+
* confirmation flag: during `'unavailable'` it can be false for a retained
|
|
578
|
+
* token/cookie-only candidate with no cached profile. Use `status` for redirects.
|
|
521
579
|
*/
|
|
522
580
|
authenticated: boolean
|
|
523
581
|
|
|
524
582
|
/**
|
|
525
|
-
* Current user
|
|
583
|
+
* Current user, or null when none is cached. In particular, an `'unavailable'`
|
|
584
|
+
* token/cookie-only restore has a retained candidate but no profile yet.
|
|
526
585
|
*/
|
|
527
586
|
user: T | null
|
|
528
587
|
|
|
@@ -555,6 +614,9 @@ to react to the server's own answer:
|
|
|
555
614
|
map, a field map with arrays, or a top-level array of messages — without
|
|
556
615
|
re-implementing the login call. A body that is not JSON (an HTML error
|
|
557
616
|
page, an empty body) arrives as `{}`.
|
|
617
|
+
- `response`: the same failed-response view as `@molecule/app-http`, with
|
|
618
|
+
`response.data === body`, so `isHttpError` and `response.data` readers work
|
|
619
|
+
on this rejection too.
|
|
558
620
|
|
|
559
621
|
```typescript
|
|
560
622
|
import { I18nError } from '@molecule/app-i18n'
|
|
@@ -580,6 +642,29 @@ interface AuthError extends I18nError {
|
|
|
580
642
|
* maps and arrays included. `{}` when the body is not JSON.
|
|
581
643
|
*/
|
|
582
644
|
body: unknown
|
|
645
|
+
|
|
646
|
+
/** The app-http-compatible view of the failed response. */
|
|
647
|
+
response: {
|
|
648
|
+
/** The same parsed value as {@link AuthError.body}. */
|
|
649
|
+
data: unknown
|
|
650
|
+
/** The same HTTP status as {@link AuthError.status}. */
|
|
651
|
+
status: number
|
|
652
|
+
/** HTTP status text supplied by the server or fetch implementation. */
|
|
653
|
+
statusText: string
|
|
654
|
+
/** Response headers as a plain object, with credential headers omitted. */
|
|
655
|
+
headers: Record<string, string>
|
|
656
|
+
/** Method and credential-redacted URL only; request bodies and headers are never retained. */
|
|
657
|
+
config: {
|
|
658
|
+
method: string
|
|
659
|
+
url: string
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/** The same translation key as {@link I18nError.i18nKey}. */
|
|
664
|
+
errorKey: string
|
|
665
|
+
|
|
666
|
+
/** A server response was received, so a non-ok response is never an abort. */
|
|
667
|
+
aborted: false
|
|
583
668
|
}
|
|
584
669
|
```
|
|
585
670
|
|
|
@@ -647,12 +732,23 @@ interface AuthClient<
|
|
|
647
732
|
* Updates the cached user object (state + persistent storage) without
|
|
648
733
|
* hitting the network. Intended for local refreshes after a per-app
|
|
649
734
|
* mutation (e.g., the user just PATCHed their own profile and the
|
|
650
|
-
* server returned the canonical row).
|
|
735
|
+
* server returned the canonical row). A non-null profile does NOT change
|
|
736
|
+
* tokens or sign the client in: `authenticated` and `status` are unchanged,
|
|
737
|
+
* so an anonymous client stays anonymous. Use {@link login} /
|
|
738
|
+
* {@link register} for a credential exchange, or {@link setSession} when
|
|
739
|
+
* the token was issued outside the client.
|
|
651
740
|
*
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
*
|
|
741
|
+
* Passing `null` on a signed-in client, or while any session operation is
|
|
742
|
+
* pending, ends the local session: it clears the access token, refresh token
|
|
743
|
+
* and cached user, stops automatic refresh, and settles `authenticated: false`
|
|
744
|
+
* with `status: 'unauthenticated'` in one notification. Every older operation
|
|
745
|
+
* loses session ownership, and a persistent sign-out marker prevents a reload
|
|
746
|
+
* from restoring its credentials or a late cookie. A late credential exchange
|
|
747
|
+
* is revoked best-effort when a logout endpoint is configured, without blocking
|
|
748
|
+
* the caller. This method does not otherwise call the server for a settled
|
|
749
|
+
* session; use {@link logout} for explicit server revocation. On a settled
|
|
750
|
+
* anonymous client, `null` only clears the cached profile and leaves tokens
|
|
751
|
+
* and auth state unchanged.
|
|
656
752
|
*/
|
|
657
753
|
setUser(user: T | null): void
|
|
658
754
|
|
|
@@ -669,10 +765,13 @@ interface AuthClient<
|
|
|
669
765
|
* which would violate the storage contract and make a stored bearer token
|
|
670
766
|
* JS-readable (XSS-exfiltratable). Pass `null` to clear it.
|
|
671
767
|
*
|
|
672
|
-
* This changes token storage only
|
|
673
|
-
*
|
|
674
|
-
*
|
|
675
|
-
*
|
|
768
|
+
* This changes token storage only: passing `null` does not by itself sign a
|
|
769
|
+
* signed-in client out, and a non-null token does not sign an anonymous
|
|
770
|
+
* client in (`authenticated` and `status` are unchanged). Use {@link logout}
|
|
771
|
+
* to end a session, or {@link setUser} with `null` for local-only sign-out.
|
|
772
|
+
* Use {@link login} / {@link register} for a credential exchange, or call
|
|
773
|
+
* {@link setSession} with the token and user to establish an already-issued
|
|
774
|
+
* session.
|
|
676
775
|
*/
|
|
677
776
|
setAccessToken(token: string | null): void
|
|
678
777
|
|
|
@@ -701,7 +800,16 @@ interface AuthClient<
|
|
|
701
800
|
login(credentials: LoginCredentials): Promise<AuthResult<T>>
|
|
702
801
|
|
|
703
802
|
/**
|
|
704
|
-
* Logs out the current user.
|
|
803
|
+
* Logs out the current user. The server request is best-effort: a missing
|
|
804
|
+
* logout route (404), any other HTTP failure, or a network error never makes
|
|
805
|
+
* this method reject. It always clears the access token, refresh token and
|
|
806
|
+
* cached user, stops automatic refresh, and publishes one settled
|
|
807
|
+
* `authenticated: false`, `status: 'unauthenticated'` transition. Every pending
|
|
808
|
+
* session operation loses ownership; a persistent marker prevents reload from
|
|
809
|
+
* restoring an older session, and late credentials are revoked best-effort.
|
|
810
|
+
*
|
|
811
|
+
* When the API has no logout route, set {@link AuthClientConfigOptions.logoutEndpoint}
|
|
812
|
+
* to `null` (or `''`) to skip the request. Local sign-out still happens.
|
|
705
813
|
*/
|
|
706
814
|
logout(): Promise<void>
|
|
707
815
|
|
|
@@ -768,35 +876,6 @@ interface AuthClient<
|
|
|
768
876
|
|
|
769
877
|
/**
|
|
770
878
|
* Re-checks a restored session against the server, in the background — the
|
|
771
|
-
* boot-time validation an app with a stored token needs when a revoked or
|
|
772
|
-
* expired token must sign the user out. Call it AFTER the first render
|
|
773
|
-
* (`initialize()` restores synchronously from storage; this costs one request).
|
|
774
|
-
*
|
|
775
|
-
* - The server confirms the user: the session is refreshed and {@link AuthState.status}
|
|
776
|
-
* stays `'authenticated'`.
|
|
777
|
-
* - The server answers 401 or 403: the token is dead — the stored session is
|
|
778
|
-
* cleared and the status becomes `'unauthenticated'`.
|
|
779
|
-
* - The server cannot confirm the session — a network failure, a 5xx, or a 404
|
|
780
|
-
* from a misconfigured {@link AuthClientConfig.currentUserEndpoint}: the
|
|
781
|
-
* session (token AND user) is KEPT and the status becomes `'unavailable'`, so
|
|
782
|
-
* the app can retry instead of signing the user out over a bad connection or a
|
|
783
|
-
* route that does not exist. The 404 error names `currentUserEndpoint`.
|
|
784
|
-
*
|
|
785
|
-
* Do not hand-write this beside the client: a parallel token/user store for a
|
|
786
|
-
* "validating"/"unavailable" flag is the race this method removes.
|
|
787
|
-
*
|
|
788
|
-
* Optional: a provider with no restorable session has nothing to validate.
|
|
789
|
-
*/
|
|
790
|
-
validateSession?(): Promise<void>
|
|
791
|
-
|
|
792
|
-
/**
|
|
793
|
-
* Resolves when the session restore started by `initialize()` has settled — the point
|
|
794
|
-
* after which the client knows whether this visitor is signed in.
|
|
795
|
-
*
|
|
796
|
-
* Resolves IMMEDIATELY when no restore is in flight: before `initialize()` is ever
|
|
797
|
-
* called, and after it has finished. A restore that failed resolves too (it settled the
|
|
798
|
-
* question), so an HTTP client can await this before every request without risking one
|
|
799
|
-
* held forever. That is what makes the fetch-before-restore race impossible: a page that
|
|
800
879
|
// … truncated — the full declaration is in node_modules/@molecule/app-auth/dist/types.d.ts
|
|
801
880
|
```
|
|
802
881
|
|
|
@@ -833,9 +912,11 @@ interface AuthClientConfigOptions<T extends object = UserProfile> {
|
|
|
833
912
|
loginEndpoint?: string
|
|
834
913
|
|
|
835
914
|
/**
|
|
836
|
-
* Logout endpoint.
|
|
915
|
+
* Logout endpoint. Defaults to `/users/logout`. Set to `null` (or `''`) when
|
|
916
|
+
* the API has no logout route: {@link AuthClient.logout} skips the request
|
|
917
|
+
* and still clears the local session.
|
|
837
918
|
*/
|
|
838
|
-
logoutEndpoint?: string
|
|
919
|
+
logoutEndpoint?: string | null
|
|
839
920
|
|
|
840
921
|
/**
|
|
841
922
|
* Register endpoint.
|
|
@@ -878,6 +959,21 @@ interface AuthClientConfigOptions<T extends object = UserProfile> {
|
|
|
878
959
|
*/
|
|
879
960
|
currentUserEndpoint?: string
|
|
880
961
|
|
|
962
|
+
/**
|
|
963
|
+
* When to probe {@link currentUserEndpoint} for an HttpOnly cookie session.
|
|
964
|
+
* The default `'hint'` probes only when the readable `mol_auth=1` cookie is
|
|
965
|
+
* present or this client already holds a cookie-session candidate. The API
|
|
966
|
+
* must set that presence hint alongside its HttpOnly cookie for automatic
|
|
967
|
+
* restoration after a full page load.
|
|
968
|
+
*
|
|
969
|
+
* Choose `'always'` for an external cookie API without that hint. Pair it with
|
|
970
|
+
* `storage: 'memory'` and the API's current-user endpoint; the request includes
|
|
971
|
+
* credentials. An anonymous load then makes a probe too. A local sign-out
|
|
972
|
+
* suppresses probes until a successful sign-in establishes another session.
|
|
973
|
+
* Network/5xx/404 failures leave a retryable candidate; 401/403 ends it.
|
|
974
|
+
*/
|
|
975
|
+
cookieRestore?: 'hint' | 'always'
|
|
976
|
+
|
|
881
977
|
/**
|
|
882
978
|
* Storage key prefix.
|
|
883
979
|
*/
|
|
@@ -888,7 +984,7 @@ interface AuthClientConfigOptions<T extends object = UserProfile> {
|
|
|
888
984
|
* `${storagePrefix}accessToken`).
|
|
889
985
|
*
|
|
890
986
|
* Set it when something outside this package reads the token at its own key —
|
|
891
|
-
* an e2e suite's contract (
|
|
987
|
+
* an e2e suite's contract (for example, `localStorage.getItem('app.jwt')`), a
|
|
892
988
|
* second library, a host page — instead of mirroring the token into
|
|
893
989
|
* `localStorage` beside the client. The refresh token and the cached user keep
|
|
894
990
|
* the prefix.
|
|
@@ -915,8 +1011,8 @@ interface AuthClientConfigOptions<T extends object = UserProfile> {
|
|
|
915
1011
|
* through `createJWTAuthClient<UserProfile, { username: string }>` — so the
|
|
916
1012
|
* body can be sent as-is under the envelope the API wants.
|
|
917
1013
|
*
|
|
918
|
-
*
|
|
919
|
-
* `{ user: { username, email, password } }`:
|
|
1014
|
+
* A nested-account API, for example, nests the payload under `user` and registers
|
|
1015
|
+
* with `{ user: { username, email, password } }`:
|
|
920
1016
|
*
|
|
921
1017
|
* ```typescript
|
|
922
1018
|
* const client = createJWTAuthClient<UserProfile, { username: string }>({
|
|
@@ -939,7 +1035,7 @@ interface AuthClientConfigOptions<T extends object = UserProfile> {
|
|
|
939
1035
|
/**
|
|
940
1036
|
* Turn an answer that carries a user into the client's
|
|
941
1037
|
* `{ accessToken, refreshToken?, user }` (default: the answer as given).
|
|
942
|
-
*
|
|
1038
|
+
* For a nested user answer, keep the wire bearer OUT of the profile, because
|
|
943
1039
|
* the client caches `user` in Web Storage where a token copy is readable by
|
|
944
1040
|
* any script on the origin:
|
|
945
1041
|
*
|
|
@@ -975,7 +1071,7 @@ interface AuthClientConfigOptions<T extends object = UserProfile> {
|
|
|
975
1071
|
* @param data - The parsed response body.
|
|
976
1072
|
* @returns The auth result.
|
|
977
1073
|
*/
|
|
978
|
-
mapAuthResponse?: (data: unknown) => AuthResult<NoInfer<T>>
|
|
1074
|
+
mapAuthResponse?: (data: unknown) => AuthResult<NoInfer<T>> | AuthChallenge
|
|
979
1075
|
|
|
980
1076
|
/**
|
|
981
1077
|
* Where the access/refresh token and the cached user are kept — the field that
|
|
@@ -986,20 +1082,6 @@ interface AuthClientConfigOptions<T extends object = UserProfile> {
|
|
|
986
1082
|
* (SSR, a Node test) the default is `'memory'`. Pass `'memory'` EXPLICITLY when
|
|
987
1083
|
* the API sets an httpOnly session cookie and you do not want a script-readable
|
|
988
1084
|
* copy: `'memory'` is a process-local store, and `initialize()` then restores
|
|
989
|
-
* through {@link AuthClientConfig.currentUserEndpoint} — the strongest
|
|
990
|
-
* configuration, because no script can read the cookie.
|
|
991
|
-
*
|
|
992
|
-
* **An app whose external contract requires the token at a specific key** — a
|
|
993
|
-
* supplied e2e suite (the RealWorld specs read `localStorage.jwtToken` in
|
|
994
|
-
* `SELECTORS.md`), a host page, a second library — sets `tokenKey: 'jwtToken'`;
|
|
995
|
-
* in a browser that is enough, because the default store is Web Storage. The
|
|
996
|
-
* session (token AND user) is then restored synchronously in `initialize()` —
|
|
997
|
-
* with no store of your own. `tokenKey` places the access token at that exact
|
|
998
|
-
* key; the refresh token and the cached user keep `storagePrefix`.
|
|
999
|
-
*
|
|
1000
|
-
* A bearer token in Web Storage is readable by any script on the origin, so an
|
|
1001
|
-
* XSS can steal it; see {@link createBrowserStorageAdapter}'s `@remarks` for the
|
|
1002
|
-
* trade and for the cookie alternative. Never answer a suite's storage key with a
|
|
1003
1085
|
// … truncated — the full declaration is in node_modules/@molecule/app-auth/dist/types.d.ts
|
|
1004
1086
|
````
|
|
1005
1087
|
|
|
@@ -1160,8 +1242,8 @@ constraint is structural, so the app can name its own fields once and pass
|
|
|
1160
1242
|
that type whole:
|
|
1161
1243
|
|
|
1162
1244
|
```typescript
|
|
1163
|
-
interface
|
|
1164
|
-
const client = createJWTAuthClient<UserProfile,
|
|
1245
|
+
interface RegistrationFields { username: string }
|
|
1246
|
+
const client = createJWTAuthClient<UserProfile, RegistrationFields>({ … })
|
|
1165
1247
|
```
|
|
1166
1248
|
|
|
1167
1249
|
A custom field may not change a built-in field's type: `email` and
|
|
@@ -1198,15 +1280,21 @@ The single value an app renders the session from — the four states every auth
|
|
|
1198
1280
|
UI needs, derived from {@link AuthState} so no caller has to combine
|
|
1199
1281
|
`initialized`/`authenticated`/`loading`/`error` itself.
|
|
1200
1282
|
|
|
1283
|
+
`status === 'loading'` is undecided: wait for it and redirect only on
|
|
1284
|
+
`status === 'unauthenticated'`. `'unavailable'` keeps the session candidate
|
|
1285
|
+
for retry; its profile can still be null. A restore failure other than
|
|
1286
|
+
401/403 never signs out.
|
|
1287
|
+
|
|
1201
1288
|
- `'loading'`: no decision yet (before `initialize()` settles). An auth
|
|
1202
1289
|
operation in flight is {@link AuthState.loading} and KEEPS the decided
|
|
1203
1290
|
status, so a page guarded on `'loading'` stays mounted while a Login or
|
|
1204
1291
|
Register request runs.
|
|
1205
1292
|
- `'authenticated'`: a session exists.
|
|
1206
1293
|
- `'unauthenticated'`: the client settled the question and nobody is signed in.
|
|
1207
|
-
- `'unavailable'`: a stored session exists but the
|
|
1208
|
-
(a network or 5xx failure
|
|
1209
|
-
is KEPT and the app can say "reconnecting" instead of signing
|
|
1294
|
+
- `'unavailable'`: a stored token or cookie-session candidate exists but the
|
|
1295
|
+
server could not confirm it (for example a network, 404, or 5xx failure);
|
|
1296
|
+
the candidate is KEPT and the app can say "reconnecting" instead of signing
|
|
1297
|
+
the user out.
|
|
1210
1298
|
|
|
1211
1299
|
```typescript
|
|
1212
1300
|
type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated' | 'unavailable'
|
|
@@ -1536,15 +1624,36 @@ function register<
|
|
|
1536
1624
|
Peer dependencies:
|
|
1537
1625
|
|
|
1538
1626
|
- `@molecule/app-bond` ^1.0.1
|
|
1627
|
+
- `@molecule/app-http` ^1.5.2
|
|
1539
1628
|
- `@molecule/app-i18n` ^1.0.1
|
|
1540
|
-
- `@molecule/app-logger` ^1.0.
|
|
1629
|
+
- `@molecule/app-logger` ^1.0.4
|
|
1541
1630
|
|
|
1542
1631
|
### Runtime Dependencies
|
|
1543
1632
|
|
|
1544
1633
|
- `@molecule/app-bond`
|
|
1634
|
+
- `@molecule/app-http`
|
|
1545
1635
|
- `@molecule/app-i18n`
|
|
1546
1636
|
- `@molecule/app-logger`
|
|
1547
1637
|
|
|
1638
|
+
**Synchronous getters for application integrations.** Read the shared client
|
|
1639
|
+
synchronously when an integration needs the raw token, auth state and current user.
|
|
1640
|
+
These reads create no second store: `getAccessToken()`
|
|
1641
|
+
returns the token, `getState().status` includes `unavailable`, and `getUser()` reads
|
|
1642
|
+
the mapped profile. The configured `tokenKey` also applies to these getters.
|
|
1643
|
+
Keep an integration's response shape local; do not persist another token or user.
|
|
1644
|
+
|
|
1645
|
+
```typescript
|
|
1646
|
+
import { getClient } from '@molecule/app-auth'
|
|
1647
|
+
const readSession = () => {
|
|
1648
|
+
const client = getClient()
|
|
1649
|
+
return {
|
|
1650
|
+
status: client.getState().status,
|
|
1651
|
+
user: client.getUser(),
|
|
1652
|
+
accessToken: client.getAccessToken(),
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
```
|
|
1656
|
+
|
|
1548
1657
|
- **An API with its own auth envelope keeps this client.** `requestBody` wraps the
|
|
1549
1658
|
login/register payload (`(kind, p) => ({ user: p })`), `mapAuthResponse` reads the
|
|
1550
1659
|
token and user out of the answer — keeping the wire bearer OUT of the profile,
|
|
@@ -1557,7 +1666,7 @@ Peer dependencies:
|
|
|
1557
1666
|
`AuthClientConfig` the client is CONSTRUCTED with
|
|
1558
1667
|
(`setClient(createJWTAuthClient({ authScheme: 'Token', … }))` in the auth bond), not
|
|
1559
1668
|
properties of a client that already exists. Do not hand-write an auth client for a spec
|
|
1560
|
-
like
|
|
1669
|
+
like this one. **Registration fields the base payload lacks (`username`, …) are the
|
|
1561
1670
|
factory's second generic** — `createJWTAuthClient<UserProfile, { username: string }>(…)` —
|
|
1562
1671
|
so `register({ username, email, password })` type-checks and the body goes out as
|
|
1563
1672
|
`{ user: { username, email, password } }`. Do not pass them as `name`/`metadata` or
|
|
@@ -66,15 +66,16 @@ export interface BrowserStorageAdapterOptions {
|
|
|
66
66
|
* - **The trade, stated plainly.** A bearer token in Web Storage is readable by
|
|
67
67
|
* any script on the origin, so one XSS is one token theft — an account takeover
|
|
68
68
|
* for the token's whole lifetime, and `localStorage` keeps the copy after the
|
|
69
|
-
* tab closes.
|
|
70
|
-
*
|
|
71
|
-
* adapter exists.
|
|
69
|
+
* tab closes. Use this adapter when a host integration requires a stored
|
|
70
|
+
* bearer, and configure its key through `tokenKey` instead of a second store.
|
|
72
71
|
* - **An httpOnly cookie session is STRONGER, and is the first choice wherever
|
|
73
72
|
* your API supports it.** Script cannot read an httpOnly cookie, so an XSS
|
|
74
73
|
* cannot exfiltrate the credential; the token stays in memory and
|
|
75
74
|
* `initialize()` restores the session through `currentUserEndpoint`
|
|
76
75
|
* (`@molecule/api-resource-user` issues exactly this cookie — pass
|
|
77
|
-
* `storage: 'memory'` when it does).
|
|
76
|
+
* `storage: 'memory'` when it does). The default restore requires its readable
|
|
77
|
+
* `mol_auth=1` presence hint. An external API without that convention uses
|
|
78
|
+
* `cookieRestore: 'always'` with its `currentUserEndpoint`. `'memory'` is then the strongest
|
|
78
79
|
* configuration. If the API sets no such cookie and you cannot change that,
|
|
79
80
|
* this adapter is the alternative — keep the token's lifetime short and rotate
|
|
80
81
|
* it on refresh.
|
|
@@ -1 +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
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AACH,eAAO,MAAM,2BAA2B,GACtC,UAAS,4BAAiC,KACzC,cA6EF,CAAA"}
|
package/dist/browser-storage.js
CHANGED
|
@@ -57,15 +57,16 @@ const warn = (message, error) => {
|
|
|
57
57
|
* - **The trade, stated plainly.** A bearer token in Web Storage is readable by
|
|
58
58
|
* any script on the origin, so one XSS is one token theft — an account takeover
|
|
59
59
|
* for the token's whole lifetime, and `localStorage` keeps the copy after the
|
|
60
|
-
* tab closes.
|
|
61
|
-
*
|
|
62
|
-
* adapter exists.
|
|
60
|
+
* tab closes. Use this adapter when a host integration requires a stored
|
|
61
|
+
* bearer, and configure its key through `tokenKey` instead of a second store.
|
|
63
62
|
* - **An httpOnly cookie session is STRONGER, and is the first choice wherever
|
|
64
63
|
* your API supports it.** Script cannot read an httpOnly cookie, so an XSS
|
|
65
64
|
* cannot exfiltrate the credential; the token stays in memory and
|
|
66
65
|
* `initialize()` restores the session through `currentUserEndpoint`
|
|
67
66
|
* (`@molecule/api-resource-user` issues exactly this cookie — pass
|
|
68
|
-
* `storage: 'memory'` when it does).
|
|
67
|
+
* `storage: 'memory'` when it does). The default restore requires its readable
|
|
68
|
+
* `mol_auth=1` presence hint. An external API without that convention uses
|
|
69
|
+
* `cookieRestore: 'always'` with its `currentUserEndpoint`. `'memory'` is then the strongest
|
|
69
70
|
* configuration. If the API sets no such cookie and you cannot change that,
|
|
70
71
|
* this adapter is the alternative — keep the token's lifetime short and rotate
|
|
71
72
|
* it on refresh.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-storage.js","sourceRoot":"","sources":["../src/browser-storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AA8BhD,gFAAgF;AAChF,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,KAAe,EAAQ,EAAE;IACtD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;QAChC,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;;YACxC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IACtC,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,2EAA2E;QAC3E,2EAA2E;QAC3E,wBAAwB;IAC1B,CAAC;AACH,CAAC,CAAA;AAED
|
|
1
|
+
{"version":3,"file":"browser-storage.js","sourceRoot":"","sources":["../src/browser-storage.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ import type { AuthClient, AuthClientConfigOptions, AuthProfileConstraint, Regist
|
|
|
33
33
|
* fields (see {@link AuthProfileConstraint}), including a profile with no `id`.
|
|
34
34
|
* The default, `UserProfile`, requires `id: string`.
|
|
35
35
|
* @template TRegister - The app's own registration fields, accepted at the top
|
|
36
|
-
* level of `register()` (e.g. `{ username: string }` for
|
|
36
|
+
* level of `register()` (e.g. `{ username: string }` for an account API).
|
|
37
37
|
* An interface and a type alias are equally valid.
|
|
38
38
|
* @param config - Auth client configuration including endpoints, storage, and refresh settings.
|
|
39
39
|
* @returns A fully configured `AuthClient` instance.
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,OAAO,KAAK,EACV,UAAU,EACV,uBAAuB,EAIvB,qBAAqB,EAQrB,kBAAkB,EAClB,WAAW,EACZ,MAAM,YAAY,CAAA;AA+RnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,mBAAmB,GAC9B,CAAC,SAAS,qBAAqB,CAAC,CAAC,CAAC,GAAG,WAAW,EAChD,SAAS,SAAS,kBAAkB,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAEtE,SAAQ,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAM,KAC/C,UAAU,CAAC,CAAC,EAAE,SAAS,CAmwCzB,CAAA"}
|