@oxyhq/core 1.11.24 → 2.0.0
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 +5 -6
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/AuthManager.js +678 -4
- package/dist/cjs/AuthManagerTypes.js +13 -0
- package/dist/cjs/CrossDomainAuth.js +45 -3
- package/dist/cjs/OxyServices.base.js +16 -0
- package/dist/cjs/i18n/locales/ar-SA.json +83 -0
- package/dist/cjs/i18n/locales/ca-ES.json +83 -0
- package/dist/cjs/i18n/locales/de-DE.json +83 -0
- package/dist/cjs/i18n/locales/en-US.json +83 -0
- package/dist/cjs/i18n/locales/es-ES.json +99 -4
- package/dist/cjs/i18n/locales/fr-FR.json +83 -0
- package/dist/cjs/i18n/locales/it-IT.json +83 -0
- package/dist/cjs/i18n/locales/ja-JP.json +83 -0
- package/dist/cjs/i18n/locales/ko-KR.json +83 -0
- package/dist/cjs/i18n/locales/locales/ar-SA.json +83 -1
- package/dist/cjs/i18n/locales/locales/ca-ES.json +83 -1
- package/dist/cjs/i18n/locales/locales/de-DE.json +83 -1
- package/dist/cjs/i18n/locales/locales/en-US.json +83 -0
- package/dist/cjs/i18n/locales/locales/es-ES.json +99 -4
- package/dist/cjs/i18n/locales/locales/fr-FR.json +83 -1
- package/dist/cjs/i18n/locales/locales/it-IT.json +83 -1
- package/dist/cjs/i18n/locales/locales/ja-JP.json +200 -117
- package/dist/cjs/i18n/locales/locales/ko-KR.json +83 -1
- package/dist/cjs/i18n/locales/locales/pt-PT.json +83 -1
- package/dist/cjs/i18n/locales/locales/zh-CN.json +83 -1
- package/dist/cjs/i18n/locales/pt-PT.json +83 -0
- package/dist/cjs/i18n/locales/zh-CN.json +83 -0
- package/dist/cjs/index.js +114 -57
- package/dist/cjs/mixins/OxyServices.auth.js +235 -0
- package/dist/cjs/mixins/OxyServices.fedcm.js +36 -0
- package/dist/cjs/mixins/OxyServices.popup.js +61 -1
- package/dist/cjs/mixins/OxyServices.user.js +18 -0
- package/dist/cjs/utils/accountUtils.js +64 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/AuthManager.js +678 -4
- package/dist/esm/AuthManagerTypes.js +12 -0
- package/dist/esm/CrossDomainAuth.js +45 -3
- package/dist/esm/OxyServices.base.js +16 -0
- package/dist/esm/i18n/locales/ar-SA.json +83 -0
- package/dist/esm/i18n/locales/ca-ES.json +83 -0
- package/dist/esm/i18n/locales/de-DE.json +83 -0
- package/dist/esm/i18n/locales/en-US.json +83 -0
- package/dist/esm/i18n/locales/es-ES.json +99 -4
- package/dist/esm/i18n/locales/fr-FR.json +83 -0
- package/dist/esm/i18n/locales/it-IT.json +83 -0
- package/dist/esm/i18n/locales/ja-JP.json +83 -0
- package/dist/esm/i18n/locales/ko-KR.json +83 -0
- package/dist/esm/i18n/locales/locales/ar-SA.json +83 -1
- package/dist/esm/i18n/locales/locales/ca-ES.json +83 -1
- package/dist/esm/i18n/locales/locales/de-DE.json +83 -1
- package/dist/esm/i18n/locales/locales/en-US.json +83 -0
- package/dist/esm/i18n/locales/locales/es-ES.json +99 -4
- package/dist/esm/i18n/locales/locales/fr-FR.json +83 -1
- package/dist/esm/i18n/locales/locales/it-IT.json +83 -1
- package/dist/esm/i18n/locales/locales/ja-JP.json +200 -117
- package/dist/esm/i18n/locales/locales/ko-KR.json +83 -1
- package/dist/esm/i18n/locales/locales/pt-PT.json +83 -1
- package/dist/esm/i18n/locales/locales/zh-CN.json +83 -1
- package/dist/esm/i18n/locales/pt-PT.json +83 -0
- package/dist/esm/i18n/locales/zh-CN.json +83 -0
- package/dist/esm/index.js +69 -26
- package/dist/esm/mixins/OxyServices.auth.js +235 -0
- package/dist/esm/mixins/OxyServices.fedcm.js +36 -0
- package/dist/esm/mixins/OxyServices.popup.js +61 -1
- package/dist/esm/mixins/OxyServices.user.js +18 -0
- package/dist/esm/utils/accountUtils.js +61 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/AuthManager.d.ts +243 -3
- package/dist/types/AuthManagerTypes.d.ts +68 -0
- package/dist/types/CrossDomainAuth.d.ts +23 -0
- package/dist/types/OxyServices.base.d.ts +14 -0
- package/dist/types/OxyServices.d.ts +7 -0
- package/dist/types/index.d.ts +28 -17
- package/dist/types/mixins/OxyServices.analytics.d.ts +1 -0
- package/dist/types/mixins/OxyServices.appData.d.ts +1 -0
- package/dist/types/mixins/OxyServices.assets.d.ts +4 -1
- package/dist/types/mixins/OxyServices.auth.d.ts +73 -1
- package/dist/types/mixins/OxyServices.contacts.d.ts +1 -0
- package/dist/types/mixins/OxyServices.developer.d.ts +1 -0
- package/dist/types/mixins/OxyServices.devices.d.ts +1 -0
- package/dist/types/mixins/OxyServices.features.d.ts +2 -5
- package/dist/types/mixins/OxyServices.fedcm.d.ts +34 -0
- package/dist/types/mixins/OxyServices.karma.d.ts +1 -0
- package/dist/types/mixins/OxyServices.language.d.ts +1 -0
- package/dist/types/mixins/OxyServices.location.d.ts +1 -0
- package/dist/types/mixins/OxyServices.managedAccounts.d.ts +1 -0
- package/dist/types/mixins/OxyServices.payment.d.ts +1 -0
- package/dist/types/mixins/OxyServices.popup.d.ts +40 -0
- package/dist/types/mixins/OxyServices.privacy.d.ts +1 -0
- package/dist/types/mixins/OxyServices.redirect.d.ts +1 -0
- package/dist/types/mixins/OxyServices.security.d.ts +1 -0
- package/dist/types/mixins/OxyServices.topics.d.ts +1 -0
- package/dist/types/mixins/OxyServices.user.d.ts +16 -1
- package/dist/types/mixins/OxyServices.utility.d.ts +1 -0
- package/dist/types/models/interfaces.d.ts +98 -0
- package/dist/types/models/session.d.ts +8 -0
- package/dist/types/utils/accountUtils.d.ts +33 -0
- package/package.json +9 -18
- package/src/AuthManager.ts +776 -7
- package/src/AuthManagerTypes.ts +72 -0
- package/src/CrossDomainAuth.ts +54 -3
- package/src/OxyServices.base.ts +17 -0
- package/src/OxyServices.ts +7 -0
- package/src/__tests__/authManager.cookiePath.test.ts +339 -0
- package/src/__tests__/authManager.security.test.ts +342 -0
- package/src/__tests__/crossDomainAuth.test.ts +191 -0
- package/src/i18n/locales/ar-SA.json +83 -1
- package/src/i18n/locales/ca-ES.json +83 -1
- package/src/i18n/locales/de-DE.json +83 -1
- package/src/i18n/locales/en-US.json +83 -0
- package/src/i18n/locales/es-ES.json +99 -4
- package/src/i18n/locales/fr-FR.json +83 -1
- package/src/i18n/locales/it-IT.json +83 -1
- package/src/i18n/locales/ja-JP.json +200 -117
- package/src/i18n/locales/ko-KR.json +83 -1
- package/src/i18n/locales/pt-PT.json +83 -1
- package/src/i18n/locales/zh-CN.json +83 -1
- package/src/index.ts +295 -112
- package/src/mixins/OxyServices.auth.ts +268 -1
- package/src/mixins/OxyServices.fedcm.ts +63 -0
- package/src/mixins/OxyServices.popup.ts +79 -1
- package/src/mixins/OxyServices.user.ts +33 -1
- package/src/mixins/__tests__/popup.test.ts +307 -0
- package/src/mixins/__tests__/sessionBaseUrl.test.ts +61 -0
- package/src/models/interfaces.ts +116 -0
- package/src/models/session.ts +8 -0
- package/src/utils/accountUtils.ts +84 -0
- package/dist/cjs/crypto/index.js +0 -22
- package/dist/cjs/shared/index.js +0 -70
- package/dist/cjs/utils/index.js +0 -26
- package/dist/esm/crypto/index.js +0 -13
- package/dist/esm/shared/index.js +0 -31
- package/dist/esm/utils/index.js +0 -7
- package/dist/types/crypto/index.d.ts +0 -11
- package/dist/types/shared/index.d.ts +0 -28
- package/dist/types/utils/index.d.ts +0 -6
- package/src/crypto/index.ts +0 -30
- package/src/shared/index.ts +0 -82
- package/src/utils/index.ts +0 -21
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { OxyServices } from './OxyServices';
|
|
10
10
|
import type { SessionLoginResponse, MinimalUserData } from './models/session';
|
|
11
|
+
import type { AuthManagerAccount, RestoreFromCookiesResult, SwitchAuthuserResult } from './AuthManagerTypes';
|
|
11
12
|
/**
|
|
12
13
|
* Storage adapter interface for platform-agnostic storage.
|
|
13
14
|
*/
|
|
@@ -36,6 +37,20 @@ export interface AuthManagerConfig {
|
|
|
36
37
|
refreshBuffer?: number;
|
|
37
38
|
/** Enable cross-tab coordination via BroadcastChannel (default: true in browsers) */
|
|
38
39
|
crossTabSync?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* "Cookie-only" mode for web apps that rely exclusively on the
|
|
42
|
+
* `oxy_rt_${authuser}` httpOnly refresh cookies and refuse to fall back
|
|
43
|
+
* to the legacy localStorage token/refresh-token path.
|
|
44
|
+
*
|
|
45
|
+
* - `false` (default): `initialize()` tries `restoreFromCookies()` first;
|
|
46
|
+
* if no accounts are restored it falls back to the legacy localStorage
|
|
47
|
+
* path (`oxy_access_token` / `oxy_session`).
|
|
48
|
+
* - `true`: `initialize()` ONLY uses `restoreFromCookies()`. No token /
|
|
49
|
+
* refresh-token / session JSON is read from or written to localStorage.
|
|
50
|
+
* This is the secure default for apps that ship the cookie path end-to-
|
|
51
|
+
* end and want to guarantee no tokens leak to JS-accessible storage.
|
|
52
|
+
*/
|
|
53
|
+
cookieOnly?: boolean;
|
|
39
54
|
}
|
|
40
55
|
/**
|
|
41
56
|
* AuthManager - Centralized authentication management.
|
|
@@ -76,6 +91,66 @@ export declare class AuthManager {
|
|
|
76
91
|
private _broadcastChannel;
|
|
77
92
|
/** Set to true when another tab broadcasts a successful refresh, so this tab can skip its own. */
|
|
78
93
|
private _otherTabRefreshed;
|
|
94
|
+
/**
|
|
95
|
+
* Identifier for this AuthManager instance (≈ "this tab"). Random hex
|
|
96
|
+
* generated at construction; advertised in every outgoing broadcast and
|
|
97
|
+
* used as the lookup key in `_knownPeerNonces`.
|
|
98
|
+
*/
|
|
99
|
+
private readonly _tabId;
|
|
100
|
+
/**
|
|
101
|
+
* Per-tab nonce, advertised in every outgoing broadcast. Receivers record
|
|
102
|
+
* the first (tabId, nonce) pair they see from a given peer; subsequent
|
|
103
|
+
* messages from the same tabId MUST carry the same nonce or they're
|
|
104
|
+
* ignored.
|
|
105
|
+
*
|
|
106
|
+
* Threat model: a same-origin XSS payload can post to the channel but can
|
|
107
|
+
* NOT read this instance's private `_broadcastNonce` field (it lives in
|
|
108
|
+
* closure, not on `window`). Forged broadcasts from XSS therefore can't
|
|
109
|
+
* impersonate this tab. A new attacker-controlled tabId trips the
|
|
110
|
+
* "first message from a new peer" branch, which is by definition trusted
|
|
111
|
+
* — so the gate raises the bar but is not a complete defence (a perfect
|
|
112
|
+
* mitigation would require message signing with a server-issued key).
|
|
113
|
+
*/
|
|
114
|
+
private readonly _broadcastNonce;
|
|
115
|
+
/**
|
|
116
|
+
* Bounded LRU of `(tabId → nonce)` pairs seen on inbound broadcasts. First
|
|
117
|
+
* sighting of a new tabId records its nonce; later messages from that
|
|
118
|
+
* tabId are rejected if the nonce doesn't match.
|
|
119
|
+
*/
|
|
120
|
+
private readonly _knownPeerNonces;
|
|
121
|
+
private static readonly _MAX_KNOWN_PEERS;
|
|
122
|
+
/**
|
|
123
|
+
* In-flight `switchAuthuser` promise. Deduplicates concurrent calls so two
|
|
124
|
+
* near-simultaneous switches don't both fire refresh requests and rotate
|
|
125
|
+
* the slot twice. Mirrors the `refreshPromise` pattern used by
|
|
126
|
+
* `refreshToken`.
|
|
127
|
+
*/
|
|
128
|
+
private _switchPromise;
|
|
129
|
+
/**
|
|
130
|
+
* Last `restoreFromCookies()` completion timestamp, keyed by the
|
|
131
|
+
* AuthManager's active authuser at the time of completion. Used to gate
|
|
132
|
+
* cross-tab cascade: a flurry of BroadcastChannel events from sibling
|
|
133
|
+
* tabs can otherwise trigger N back-to-back snapshots and rotate every
|
|
134
|
+
* slot's access token N times.
|
|
135
|
+
*/
|
|
136
|
+
private readonly _lastRestoreAt;
|
|
137
|
+
private static readonly _RESTORE_DEBOUNCE_MS;
|
|
138
|
+
/**
|
|
139
|
+
* In-memory registry of every device-local account the AuthManager knows
|
|
140
|
+
* about, keyed by `authuser` slot index. Populated by:
|
|
141
|
+
* - `restoreFromCookies()` (cold boot)
|
|
142
|
+
* - `switchAuthuser()` (per-account rotation)
|
|
143
|
+
* - `handleAuthSuccess()` (fresh login when the server response carries
|
|
144
|
+
* an `authuser` field)
|
|
145
|
+
* Access tokens live ONLY here in the cookie path — they are never
|
|
146
|
+
* persisted to localStorage.
|
|
147
|
+
*/
|
|
148
|
+
private accounts;
|
|
149
|
+
/**
|
|
150
|
+
* Currently-active `authuser` slot in the cookie path. `null` means either
|
|
151
|
+
* the cookie path hasn't been initialised yet, or no slots are signed in.
|
|
152
|
+
*/
|
|
153
|
+
private activeAuthuser;
|
|
79
154
|
constructor(oxyServices: OxyServices, config?: AuthManagerConfig);
|
|
80
155
|
/**
|
|
81
156
|
* Initialize BroadcastChannel for cross-tab token refresh coordination.
|
|
@@ -87,9 +162,38 @@ export declare class AuthManager {
|
|
|
87
162
|
*/
|
|
88
163
|
private _handleCrossTabMessage;
|
|
89
164
|
/**
|
|
90
|
-
* Broadcast a message to other tabs.
|
|
165
|
+
* Broadcast a message to other tabs. Always stamps this tab's `tabId` and
|
|
166
|
+
* `nonce` onto the message so receivers can run the cross-tab nonce gate.
|
|
91
167
|
*/
|
|
92
168
|
private _broadcast;
|
|
169
|
+
/**
|
|
170
|
+
* Generate `bytes` bytes of cryptographic randomness encoded as lowercase
|
|
171
|
+
* hex. Prefers Web Crypto's `getRandomValues` when available (browser /
|
|
172
|
+
* modern Node); falls back to `Math.random` ONLY in environments without
|
|
173
|
+
* Web Crypto (the resulting nonce is still unguessable to a same-origin
|
|
174
|
+
* XSS payload — the goal is unforgeability across tabs, not cryptographic
|
|
175
|
+
* secrecy across the network).
|
|
176
|
+
*/
|
|
177
|
+
private static _randomHex;
|
|
178
|
+
/**
|
|
179
|
+
* Validate an inbound broadcast against the cross-tab nonce gate.
|
|
180
|
+
*
|
|
181
|
+
* Returns `true` when the message should be honoured, `false` when it
|
|
182
|
+
* MUST be ignored:
|
|
183
|
+
* - Message is missing `tabId` or `nonce` → ignore (forged or
|
|
184
|
+
* mismatched-version sibling tab).
|
|
185
|
+
* - First sighting of `tabId` → record the nonce and honour the message
|
|
186
|
+
* (trust-on-first-use, the best we can do without a shared secret).
|
|
187
|
+
* - Subsequent message from the same `tabId` with the SAME nonce →
|
|
188
|
+
* honour.
|
|
189
|
+
* - Subsequent message from the same `tabId` with a DIFFERENT nonce →
|
|
190
|
+
* ignore (the canonical "forged broadcast" case — a same-origin XSS
|
|
191
|
+
* payload can't read the real tab's `_broadcastNonce`).
|
|
192
|
+
*
|
|
193
|
+
* Echoes of this tab's own broadcasts (same `tabId`) are also dropped so
|
|
194
|
+
* we don't react to our own messages.
|
|
195
|
+
*/
|
|
196
|
+
private _acceptBroadcast;
|
|
93
197
|
/**
|
|
94
198
|
* Get default storage based on environment.
|
|
95
199
|
*/
|
|
@@ -147,11 +251,147 @@ export declare class AuthManager {
|
|
|
147
251
|
*/
|
|
148
252
|
getAuthMethod(): Promise<AuthMethod | null>;
|
|
149
253
|
/**
|
|
150
|
-
* Initialize auth state
|
|
254
|
+
* Initialize auth state on app startup.
|
|
151
255
|
*
|
|
152
|
-
*
|
|
256
|
+
* Order of operations:
|
|
257
|
+
* 1. Try the cookie path via `restoreFromCookies()`. This is the
|
|
258
|
+
* preferred path because the httpOnly refresh cookies are
|
|
259
|
+
* cross-tab, persist across hard reloads, and don't expose any
|
|
260
|
+
* refresh-token material to JS.
|
|
261
|
+
* 2. If the cookie path yielded zero accounts AND `cookieOnly` is
|
|
262
|
+
* `false`, fall back to the legacy localStorage path
|
|
263
|
+
* (`oxy_access_token` / `oxy_session`) for backwards compatibility
|
|
264
|
+
* with apps that haven't migrated to the cookie endpoint yet.
|
|
265
|
+
* 3. If `cookieOnly` is `true`, skip the legacy fallback entirely.
|
|
266
|
+
* This guarantees no tokens or refresh tokens are ever read from
|
|
267
|
+
* or written to JS-accessible storage.
|
|
268
|
+
*
|
|
269
|
+
* Returns the active user on success, or `null` when neither path
|
|
270
|
+
* restored a session.
|
|
153
271
|
*/
|
|
154
272
|
initialize(): Promise<MinimalUserData | null>;
|
|
273
|
+
/**
|
|
274
|
+
* Read the persisted active `authuser` slot index. Returns `null` when
|
|
275
|
+
* none is persisted, the value is corrupt, or the storage adapter has no
|
|
276
|
+
* record. Storage failures are non-fatal: the cookie path falls back to
|
|
277
|
+
* "lowest authuser" deterministic selection.
|
|
278
|
+
*/
|
|
279
|
+
private readActiveAuthuser;
|
|
280
|
+
/**
|
|
281
|
+
* Persist the active `authuser` slot index. No-ops on storage failure
|
|
282
|
+
* (e.g. Safari private mode, native SecureStore unavailable) — this is
|
|
283
|
+
* best-effort UX persistence, not authoritative state.
|
|
284
|
+
*/
|
|
285
|
+
private writeActiveAuthuser;
|
|
286
|
+
/**
|
|
287
|
+
* Clear the persisted active `authuser` so the next cold boot starts from
|
|
288
|
+
* a clean slate (used on full sign-out).
|
|
289
|
+
*/
|
|
290
|
+
private clearActiveAuthuser;
|
|
291
|
+
/**
|
|
292
|
+
* Build a `MinimalUserData` from a `RefreshAllAccount`. Returns `null` when
|
|
293
|
+
* the wire entry has no user shape (legacy `/auth/refresh` fallback) — the
|
|
294
|
+
* AuthManager's caller is expected to hydrate via `/users/me` in that
|
|
295
|
+
* case.
|
|
296
|
+
*/
|
|
297
|
+
private static toMinimalUser;
|
|
298
|
+
/**
|
|
299
|
+
* Hydrate the user shape for a slot whose AuthManagerAccount currently has
|
|
300
|
+
* `user: null` (legacy refresh fallback, or a switch onto a previously
|
|
301
|
+
* unknown slot). Calls `/users/me` with the slot's freshly-planted access
|
|
302
|
+
* token already on the HTTP client; merges the result back into the
|
|
303
|
+
* registry entry. Network failures are non-fatal — the slot remains with
|
|
304
|
+
* `user: null` and the UI is expected to render the public-key fallback
|
|
305
|
+
* handle until a later restore picks the real user shape up.
|
|
306
|
+
*/
|
|
307
|
+
private _hydrateUnknownUser;
|
|
308
|
+
/**
|
|
309
|
+
* Snapshot of the registered cookie-path accounts, sorted by `authuser`
|
|
310
|
+
* ascending (canonical order). Mutating the returned array does not
|
|
311
|
+
* affect AuthManager state.
|
|
312
|
+
*/
|
|
313
|
+
getAccounts(): AuthManagerAccount[];
|
|
314
|
+
/**
|
|
315
|
+
* The slot index that is currently active in the cookie path, or `null`
|
|
316
|
+
* if the cookie path hasn't been initialised or no slots are signed in.
|
|
317
|
+
*/
|
|
318
|
+
getActiveAuthuser(): number | null;
|
|
319
|
+
/**
|
|
320
|
+
* Convenience: the AuthManagerAccount currently flagged active.
|
|
321
|
+
*/
|
|
322
|
+
getActiveAccount(): AuthManagerAccount | null;
|
|
323
|
+
/**
|
|
324
|
+
* Restore every device-local account from the httpOnly refresh cookies.
|
|
325
|
+
*
|
|
326
|
+
* Calls `oxyServices.refreshAllSessions()` (`POST /auth/refresh-all` with
|
|
327
|
+
* `credentials: 'include'`). The server rotates every presented
|
|
328
|
+
* `oxy_rt_${authuser}` cookie in parallel and returns one entry per
|
|
329
|
+
* VALID slot. The SDK transparently falls back to the legacy single-slot
|
|
330
|
+
* `/auth/refresh` against older servers (handled inside
|
|
331
|
+
* `refreshAllSessions`).
|
|
332
|
+
*
|
|
333
|
+
* Plants the active account's access token on the shared HTTP client;
|
|
334
|
+
* sibling slots' tokens stay in the in-memory registry so a later
|
|
335
|
+
* `switchAuthuser()` can hot-swap them without a network round-trip.
|
|
336
|
+
*
|
|
337
|
+
* The persisted `oxy_active_authuser` slot wins when it matches a
|
|
338
|
+
* returned account; otherwise the lowest returned `authuser` is chosen
|
|
339
|
+
* deterministically.
|
|
340
|
+
*
|
|
341
|
+
* Returns `{ accounts: [], activeAuthuser: null }` on any failure or
|
|
342
|
+
* empty snapshot — callers treat that as "no signed-in accounts" and
|
|
343
|
+
* proceed unauthenticated. State is NOT cleared on failure; existing
|
|
344
|
+
* accounts (if any) remain intact.
|
|
345
|
+
*/
|
|
346
|
+
restoreFromCookies(): Promise<RestoreFromCookiesResult>;
|
|
347
|
+
/**
|
|
348
|
+
* Switch the active account to a different device-local slot.
|
|
349
|
+
*
|
|
350
|
+
* Calls `oxyServices.refreshTokenViaCookie({ authuser })` to mint a fresh
|
|
351
|
+
* access token from the slot's httpOnly cookie, updates the in-memory
|
|
352
|
+
* registry entry, plants the token on the HTTP client, persists the new
|
|
353
|
+
* active slot, and broadcasts cross-tab.
|
|
354
|
+
*
|
|
355
|
+
* Throws when the slot's refresh cookie is missing / expired / reused
|
|
356
|
+
* (the SDK returns `null` from `refreshTokenViaCookie` in that case, and
|
|
357
|
+
* we surface it as an `Error` so callers can clean up the slot from
|
|
358
|
+
* their UI).
|
|
359
|
+
*/
|
|
360
|
+
switchAuthuser(authuser: number): Promise<SwitchAuthuserResult>;
|
|
361
|
+
private _doSwitchAuthuser;
|
|
362
|
+
/**
|
|
363
|
+
* Sign out a single device-local slot.
|
|
364
|
+
*
|
|
365
|
+
* Calls `oxyServices.logoutSessionByAuthuser(authuser)`: server-side
|
|
366
|
+
* revokes the slot's refresh-token family and clears the
|
|
367
|
+
* `oxy_rt_${authuser}` cookie via `Set-Cookie`. The slot is removed from
|
|
368
|
+
* the in-memory registry. If the slot was active, the next lowest
|
|
369
|
+
* remaining authuser becomes active (or `null` when none remain).
|
|
370
|
+
*/
|
|
371
|
+
signOutAuthuser(authuser: number): Promise<void>;
|
|
372
|
+
/**
|
|
373
|
+
* Sign out EVERY device-local account on this device.
|
|
374
|
+
*
|
|
375
|
+
* Calls `oxyServices.logoutAllSessionsViaCookie()`: server-side revokes
|
|
376
|
+
* every presented family and `Set-Cookie`s an immediate expiry for every
|
|
377
|
+
* recognised `oxy_rt_${n}` slot AND the legacy `oxy_rt` cookie. The
|
|
378
|
+
* in-memory registry is wiped, the active slot is cleared, and the
|
|
379
|
+
* persisted `oxy_active_authuser` is removed so the next cold boot
|
|
380
|
+
* starts fresh.
|
|
381
|
+
*/
|
|
382
|
+
signOutAllViaCookies(): Promise<void>;
|
|
383
|
+
/**
|
|
384
|
+
* Schedule an auto-refresh for the cookie path on the active slot. Reuses
|
|
385
|
+
* the same single `refreshTimer` as the legacy path (the AuthManager has
|
|
386
|
+
* exactly ONE active slot at a time, so one timer suffices).
|
|
387
|
+
*/
|
|
388
|
+
private setupCookieRefresh;
|
|
389
|
+
/**
|
|
390
|
+
* Decode the session id from an unverified JWT access token. Decode-only
|
|
391
|
+
* (no signature verification) — the server already verified the
|
|
392
|
+
* signature when minting the token. Returns `null` on malformed input.
|
|
393
|
+
*/
|
|
394
|
+
private static decodeSessionIdFromAccessToken;
|
|
155
395
|
/**
|
|
156
396
|
* Destroy the auth manager and clean up resources.
|
|
157
397
|
*/
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthManager — public types for the multi-account cookie path.
|
|
3
|
+
*
|
|
4
|
+
* Lives in its own module (rather than the 670-line `models/interfaces.ts`)
|
|
5
|
+
* so consumers can `import type` exactly the multi-account surface without
|
|
6
|
+
* pulling in the full interfaces graph, and so `AuthManager.ts` stays
|
|
7
|
+
* decoupled from the wire shapes — these types re-state the wire as the
|
|
8
|
+
* AuthManager's in-memory representation.
|
|
9
|
+
*
|
|
10
|
+
* @module core/AuthManagerTypes
|
|
11
|
+
*/
|
|
12
|
+
import type { RefreshAllAccountUser } from './models/interfaces';
|
|
13
|
+
/**
|
|
14
|
+
* One device-local account known to `AuthManager` in the cookie path.
|
|
15
|
+
*
|
|
16
|
+
* Built from a `POST /auth/refresh-all` entry, OR from a single
|
|
17
|
+
* `POST /auth/refresh?authuser=N` rotation after a switch, OR from a
|
|
18
|
+
* `handleAuthSuccess` call after a fresh login. The `accessToken` is held in
|
|
19
|
+
* memory only — the refresh token never enters JS (it lives in the httpOnly
|
|
20
|
+
* `oxy_rt_${authuser}` cookie).
|
|
21
|
+
*/
|
|
22
|
+
export interface AuthManagerAccount {
|
|
23
|
+
/** Device-local cookie slot index (0..N-1). */
|
|
24
|
+
authuser: number;
|
|
25
|
+
/** Server-side session id this slot is bound to. */
|
|
26
|
+
sessionId: string;
|
|
27
|
+
/**
|
|
28
|
+
* Projected user shape from the wire (username/avatar/color/email).
|
|
29
|
+
*
|
|
30
|
+
* `null` when a refresh-via-cookie planted a fresh access token for a slot
|
|
31
|
+
* that the AuthManager has no prior in-memory user metadata for — e.g. the
|
|
32
|
+
* legacy `/auth/refresh` 404 fallback path inside `refreshAllSessions`, or
|
|
33
|
+
* a `switchAuthuser` against a slot that wasn't present in the previous
|
|
34
|
+
* `restoreFromCookies` snapshot. Callers (or the AuthManager itself) are
|
|
35
|
+
* expected to hydrate the user shape via `getCurrentUser()` after the token
|
|
36
|
+
* is planted; the chooser UI must render the public-key fallback handle
|
|
37
|
+
* until the hydration completes.
|
|
38
|
+
*/
|
|
39
|
+
user: RefreshAllAccountUser | null;
|
|
40
|
+
/** Currently-valid access token for this slot (in-memory only). */
|
|
41
|
+
accessToken: string;
|
|
42
|
+
/** ISO-8601 expiry of the access token. */
|
|
43
|
+
expiresAt: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Outcome of `AuthManager.restoreFromCookies()`.
|
|
47
|
+
*
|
|
48
|
+
* `accounts` is sorted by `authuser` ascending (matching the server's
|
|
49
|
+
* canonical ordering). `activeAuthuser` is whichever slot the AuthManager
|
|
50
|
+
* picked as active — usually the persisted `oxy_active_authuser` if it
|
|
51
|
+
* matched a returned slot, otherwise the lowest returned `authuser`, or
|
|
52
|
+
* `null` if no accounts were restored.
|
|
53
|
+
*/
|
|
54
|
+
export interface RestoreFromCookiesResult {
|
|
55
|
+
accounts: AuthManagerAccount[];
|
|
56
|
+
activeAuthuser: number | null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Outcome of `AuthManager.switchAuthuser()`.
|
|
60
|
+
*
|
|
61
|
+
* Mirrors the wire `RefreshCookieResponse` but with `authuser` narrowed to
|
|
62
|
+
* `number` (the SDK boundary normalises the legacy `null` slot to `0`).
|
|
63
|
+
*/
|
|
64
|
+
export interface SwitchAuthuserResult {
|
|
65
|
+
accessToken: string;
|
|
66
|
+
expiresAt: string;
|
|
67
|
+
authuser: number;
|
|
68
|
+
}
|
|
@@ -51,6 +51,13 @@ export interface CrossDomainAuthOptions {
|
|
|
51
51
|
* Callback when auth method is selected
|
|
52
52
|
*/
|
|
53
53
|
onMethodSelected?: (method: 'fedcm' | 'popup' | 'redirect') => void;
|
|
54
|
+
/**
|
|
55
|
+
* A popup window the caller already opened SYNCHRONOUSLY in the user-gesture
|
|
56
|
+
* handler. Forwarded to `OxyServices.signInWithPopup` so the popup is not
|
|
57
|
+
* blocked by Chrome after any prior `await` (FedCM / silent SSO) has
|
|
58
|
+
* consumed the transient user activation. See `OxyServices.openBlankPopup`.
|
|
59
|
+
*/
|
|
60
|
+
popup?: Window | null;
|
|
54
61
|
}
|
|
55
62
|
export declare class CrossDomainAuth {
|
|
56
63
|
private oxyServices;
|
|
@@ -67,6 +74,14 @@ export declare class CrossDomainAuth {
|
|
|
67
74
|
* @returns Session with user data and access token
|
|
68
75
|
*/
|
|
69
76
|
signIn(options?: CrossDomainAuthOptions): Promise<SessionLoginResponse | null>;
|
|
77
|
+
/**
|
|
78
|
+
* Close a caller-supplied popup window that is no longer needed (e.g. the
|
|
79
|
+
* resolved auth method didn't end up using it). Safe against null / already
|
|
80
|
+
* closed handles.
|
|
81
|
+
*
|
|
82
|
+
* @private
|
|
83
|
+
*/
|
|
84
|
+
private closeOrphanPopup;
|
|
70
85
|
/**
|
|
71
86
|
* Automatic sign-in with progressive enhancement
|
|
72
87
|
*
|
|
@@ -112,6 +127,14 @@ export declare class CrossDomainAuth {
|
|
|
112
127
|
* For redirect method - restores previously authenticated session from localStorage
|
|
113
128
|
*/
|
|
114
129
|
restoreSession(): boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Open a blank popup SYNCHRONOUSLY (call from a raw user-gesture handler
|
|
132
|
+
* BEFORE any `await`). Returns `null` if the popup was blocked. Pass the
|
|
133
|
+
* handle into `signIn({ popup })` / `signInWithPopup({ popup })` so the
|
|
134
|
+
* popup is not blocked by Chrome after any prior `await` consumed the
|
|
135
|
+
* transient user activation. Delegates to `OxyServices.openBlankPopup`.
|
|
136
|
+
*/
|
|
137
|
+
openBlankPopup(width?: number, height?: number): Window | null;
|
|
115
138
|
/**
|
|
116
139
|
* Check if FedCM is supported in current browser
|
|
117
140
|
*/
|
|
@@ -21,6 +21,20 @@ export declare class OxyServicesBase {
|
|
|
21
21
|
* Get the configured Oxy API base URL
|
|
22
22
|
*/
|
|
23
23
|
getBaseURL(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Get the base URL the SDK's first-party session/refresh calls should target.
|
|
26
|
+
*
|
|
27
|
+
* Returns the configured `sessionBaseUrl` when provided, otherwise falls back
|
|
28
|
+
* to the API `baseURL` (`getBaseURL()`). Per the 2026 session architecture
|
|
29
|
+
* (docs/SESSION-ARCHITECTURE.md), non-`oxy.so` apps point this at their own
|
|
30
|
+
* same-site backend (e.g. `https://api.mention.earth`) whose session bridge
|
|
31
|
+
* forwards the user's refresh credential to `api.oxy.so`; `*.oxy.so` apps
|
|
32
|
+
* leave it unset so it resolves to `https://api.oxy.so` and nothing changes.
|
|
33
|
+
*
|
|
34
|
+
* This is additive: it only exposes configuration for `@oxyhq/services` to
|
|
35
|
+
* consume in a later phase. No refresh/auth logic in core reads it yet.
|
|
36
|
+
*/
|
|
37
|
+
getSessionBaseUrl(): string;
|
|
24
38
|
/**
|
|
25
39
|
* Get the HTTP service instance
|
|
26
40
|
* Useful for advanced use cases where direct access to the HTTP service is needed
|
|
@@ -117,6 +117,13 @@ export interface OxyServices extends InstanceType<ReturnType<typeof composeOxySe
|
|
|
117
117
|
getFedCMConfig(): FedCMConfig;
|
|
118
118
|
signInWithPopup(options?: PopupAuthOptions): Promise<SessionLoginResponse>;
|
|
119
119
|
signUpWithPopup(options?: PopupAuthOptions): Promise<SessionLoginResponse>;
|
|
120
|
+
/**
|
|
121
|
+
* Open a blank popup SYNCHRONOUSLY (call from a raw user-gesture handler
|
|
122
|
+
* BEFORE any `await`). Returns `null` if the popup was blocked. Pass the
|
|
123
|
+
* handle into `signInWithPopup({ popup })` to navigate it to auth.oxy.so
|
|
124
|
+
* after the async portion of the sign-in flow runs.
|
|
125
|
+
*/
|
|
126
|
+
openBlankPopup(width?: number, height?: number): Window | null;
|
|
120
127
|
signInWithRedirect(options?: RedirectAuthOptions): void;
|
|
121
128
|
signUpWithRedirect(options?: RedirectAuthOptions): void;
|
|
122
129
|
auth(options?: {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -12,31 +12,44 @@
|
|
|
12
12
|
*
|
|
13
13
|
* const user = await oxyClient.signIn(publicKey);
|
|
14
14
|
* ```
|
|
15
|
+
*
|
|
16
|
+
* Every export below is NOMINAL — no `export *`, no barrels, no compat shims.
|
|
17
|
+
* If a symbol does not appear here, it is NOT part of the public API.
|
|
15
18
|
*/
|
|
16
19
|
import './crypto/polyfill';
|
|
17
20
|
export { OxyServices, OxyAuthenticationError, OxyAuthenticationTimeoutError } from './OxyServices';
|
|
18
21
|
export { OXY_CLOUD_URL, oxyClient } from './OxyServices';
|
|
19
22
|
export { AuthManager, createAuthManager } from './AuthManager';
|
|
20
|
-
export type { StorageAdapter, AuthStateChangeCallback, AuthMethod, AuthManagerConfig } from './AuthManager';
|
|
23
|
+
export type { StorageAdapter, AuthStateChangeCallback, AuthMethod, AuthManagerConfig, } from './AuthManager';
|
|
24
|
+
export type { AuthManagerAccount, RestoreFromCookiesResult, SwitchAuthuserResult, } from './AuthManagerTypes';
|
|
21
25
|
export { CrossDomainAuth, createCrossDomainAuth } from './CrossDomainAuth';
|
|
22
26
|
export type { CrossDomainAuthOptions } from './CrossDomainAuth';
|
|
23
|
-
export type { FedCMAuthOptions, FedCMConfig } from './mixins/OxyServices.fedcm';
|
|
27
|
+
export type { FedCMAuthOptions, FedCMConfig, AuthorizedApp } from './mixins/OxyServices.fedcm';
|
|
24
28
|
export type { PopupAuthOptions } from './mixins/OxyServices.popup';
|
|
25
29
|
export type { RedirectAuthOptions } from './mixins/OxyServices.redirect';
|
|
26
30
|
export { ServiceCredentialMismatchError } from './mixins/OxyServices.auth';
|
|
27
31
|
export type { ServiceTokenResponse } from './mixins/OxyServices.auth';
|
|
28
32
|
export type { ServiceApp, ServiceActingAsVerification } from './mixins/OxyServices.utility';
|
|
29
|
-
export type { CreateManagedAccountInput, ManagedAccountManager, ManagedAccount } from './mixins/OxyServices.managedAccounts';
|
|
30
|
-
export type { ContactDiscoveryMatch, ContactDiscoveryResponse } from './mixins/OxyServices.contacts';
|
|
33
|
+
export type { CreateManagedAccountInput, ManagedAccountManager, ManagedAccount, } from './mixins/OxyServices.managedAccounts';
|
|
34
|
+
export type { ContactDiscoveryMatch, ContactDiscoveryResponse, } from './mixins/OxyServices.contacts';
|
|
31
35
|
export { OxyAppDataIdentifierError } from './mixins/OxyServices.appData';
|
|
32
|
-
export {
|
|
33
|
-
export type {
|
|
34
|
-
export
|
|
35
|
-
export
|
|
36
|
-
export type {
|
|
37
|
-
export {
|
|
36
|
+
export { SessionSyncRequiredError, AuthenticationFailedError, ensureValidToken, isAuthenticationError, withAuthErrorHandling, authenticatedApiCall, } from './utils/authHelpers';
|
|
37
|
+
export type { HandleApiErrorOptions } from './utils/authHelpers';
|
|
38
|
+
export { mergeSessions, normalizeAndSortSessions, sessionsArraysEqual, } from './utils/sessionUtils';
|
|
39
|
+
export type { ClientSession, StorageKeys, MinimalUserData, SessionLoginResponse, } from './models/session';
|
|
40
|
+
export type { RefreshAllResponse, RefreshAllAccount, RefreshAllAccountUser, RefreshCookieResponse, } from './models/interfaces';
|
|
41
|
+
export { KeyManager, IdentityAlreadyExistsError, IdentityPersistError, } from './crypto/keyManager';
|
|
42
|
+
export type { KeyPair } from './crypto/keyManager';
|
|
43
|
+
export { SignatureService } from './crypto/signatureService';
|
|
44
|
+
export type { SignedMessage, AuthChallenge } from './crypto/signatureService';
|
|
45
|
+
export { RecoveryPhraseService } from './crypto/recoveryPhrase';
|
|
46
|
+
export type { RecoveryPhraseResult } from './crypto/recoveryPhrase';
|
|
38
47
|
export { DeviceManager } from './utils/deviceManager';
|
|
39
48
|
export type { DeviceFingerprint, StoredDeviceInfo } from './utils/deviceManager';
|
|
49
|
+
export type { OxyConfig, PrivacySettings, NotificationPreferences, UserPreferences, User, LoginResponse, Notification, Wallet, Transaction, BlockedUser, RestrictedUser, TransferFundsRequest, PurchaseRequest, WithdrawalRequest, TransactionResponse, PaginationInfo, SearchProfilesResponse, KarmaRule, KarmaHistory, KarmaLeaderboardEntry, KarmaAwardRequest, ApiError, PaymentMethod, PaymentRequest, PaymentResponse, AnalyticsData, FollowerDetails, ContentViewer, FileMetadata, FileUploadResponse, FileListResponse, FileUpdateRequest, FileDeleteResponse, RNFileDescriptor, AssetUploadInput, FileVisibility, AssetLink, AssetMetadata, AssetVariant, Asset, AssetInitRequest, AssetInitResponse, AssetCompleteRequest, AssetLinkRequest, AssetUnlinkRequest, AssetUrlResponse, AssetDeleteSummary, AssetUpdateVisibilityRequest, AssetUpdateVisibilityResponse, AccountStorageCategoryUsage, AccountStorageUsageResponse, SecurityEventType, SecurityEventSeverity, SecurityActivity, SecurityActivityResponse, AssetUploadProgress, DeviceSession, DeviceSessionsResponse, DeviceSessionLogoutResponse, UpdateDeviceNameResponse, } from './models/interfaces';
|
|
50
|
+
export { SECURITY_EVENT_SEVERITY_MAP } from './models/interfaces';
|
|
51
|
+
export { TopicType, TopicSource } from './models/Topic';
|
|
52
|
+
export type { TopicData, TopicTranslation } from './models/Topic';
|
|
40
53
|
export { SUPPORTED_LANGUAGES, getLanguageMetadata, getLanguageName, getNativeLanguageName, normalizeLanguageCode, isRTLLocale, } from './utils/languageUtils';
|
|
41
54
|
export type { LanguageMetadata } from './utils/languageUtils';
|
|
42
55
|
export { getPlatformOS, setPlatformOS, isWeb, isNative, isIOS, isAndroid, } from './utils/platform';
|
|
@@ -49,18 +62,16 @@ export { DEFAULT_CIRCUIT_BREAKER_CONFIG, createCircuitBreakerState, calculateBac
|
|
|
49
62
|
export type { CircuitBreakerState, CircuitBreakerConfig } from './shared/utils/networkUtils';
|
|
50
63
|
export { isDev, debugLog, debugWarn, debugError, createDebugLogger, } from './shared/utils/debugUtils';
|
|
51
64
|
export { translate } from './i18n';
|
|
52
|
-
export {
|
|
53
|
-
export type {
|
|
54
|
-
export { mergeSessions, normalizeAndSortSessions, sessionsArraysEqual } from './utils/sessionUtils';
|
|
55
|
-
export { packageInfo } from './constants/version';
|
|
56
|
-
export * from './utils/apiUtils';
|
|
65
|
+
export { buildSearchParams, buildUrl, buildPaginationParams, safeJsonParse, } from './utils/apiUtils';
|
|
66
|
+
export type { PaginationParams, ApiResponse, ErrorResponse, } from './utils/apiUtils';
|
|
57
67
|
export { ErrorCodes, createApiError, handleHttpError, validateRequiredFields, } from './utils/errorUtils';
|
|
58
68
|
export { retryAsync } from './utils/asyncUtils';
|
|
59
|
-
export
|
|
69
|
+
export { EMAIL_REGEX, USERNAME_REGEX, PASSWORD_REGEX, isValidEmail, isValidUsername, isValidPassword, isRequiredString, isRequiredNumber, isRequiredBoolean, isValidArray, isValidObject, isValidUUID, isValidURL, isValidDate, isValidFileSize, isValidFileType, sanitizeString, sanitizeHTML, isValidObjectId, validateAndSanitizeUserInput, } from './utils/validationUtils';
|
|
60
70
|
export { logger, LogLevel, logAuth, logApi, logSession, logUser, logDevice, logPayment, logPerformance, } from './utils/loggerUtils';
|
|
61
71
|
export type { LogContext } from './utils/loggerUtils';
|
|
62
72
|
export { updateAvatarVisibility } from './utils/avatarUtils';
|
|
63
|
-
export { buildAccountsArray, createQuickAccount, getAccountDisplayName, getAccountFallbackHandle, formatPublicKeyHandle, } from './utils/accountUtils';
|
|
73
|
+
export { buildAccountsArray, createQuickAccount, getAccountDisplayName, getAccountFallbackHandle, formatPublicKeyHandle, mergeAccountsFromRefreshAll, getAccountColor, } from './utils/accountUtils';
|
|
64
74
|
export type { QuickAccount, DisplayNameUserShape } from './utils/accountUtils';
|
|
75
|
+
export { packageInfo } from './constants/version';
|
|
65
76
|
import { OxyServices } from './OxyServices';
|
|
66
77
|
export default OxyServices;
|
|
@@ -25,6 +25,7 @@ export declare function OxyServicesAnalyticsMixin<T extends typeof OxyServicesBa
|
|
|
25
25
|
__resetTokensForTests(): void;
|
|
26
26
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
27
27
|
getBaseURL(): string;
|
|
28
|
+
getSessionBaseUrl(): string;
|
|
28
29
|
getClient(): import("../HttpService").HttpService;
|
|
29
30
|
getMetrics(): {
|
|
30
31
|
totalRequests: number;
|
|
@@ -61,6 +61,7 @@ export declare function OxyServicesAppDataMixin<T extends typeof OxyServicesBase
|
|
|
61
61
|
__resetTokensForTests(): void;
|
|
62
62
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
63
63
|
getBaseURL(): string;
|
|
64
|
+
getSessionBaseUrl(): string;
|
|
64
65
|
getClient(): import("../HttpService").HttpService;
|
|
65
66
|
getMetrics(): {
|
|
66
67
|
totalRequests: number;
|
|
@@ -98,6 +98,7 @@ export declare function OxyServicesAssetsMixin<T extends typeof OxyServicesBase>
|
|
|
98
98
|
__resetTokensForTests(): void;
|
|
99
99
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
100
100
|
getBaseURL(): string;
|
|
101
|
+
getSessionBaseUrl(): string;
|
|
101
102
|
getClient(): import("../HttpService").HttpService;
|
|
102
103
|
getMetrics(): {
|
|
103
104
|
totalRequests: number;
|
|
@@ -131,7 +132,9 @@ export declare function OxyServicesAssetsMixin<T extends typeof OxyServicesBase>
|
|
|
131
132
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
132
133
|
maxRetries?: number;
|
|
133
134
|
retryDelay?: number;
|
|
134
|
-
authTimeoutMs
|
|
135
|
+
authTimeoutMs? /**
|
|
136
|
+
* Get asset metadata
|
|
137
|
+
*/: number;
|
|
135
138
|
}): Promise<T_1>;
|
|
136
139
|
validate(): Promise<boolean>;
|
|
137
140
|
handleError(error: unknown): Error;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Supports password-based login (email/username) and public key challenge-response.
|
|
5
5
|
*/
|
|
6
|
-
import type { User } from '../models/interfaces';
|
|
6
|
+
import type { User, RefreshAllResponse, RefreshCookieResponse } from '../models/interfaces';
|
|
7
7
|
import type { SessionLoginResponse } from '../models/session';
|
|
8
8
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
9
9
|
export interface ChallengeResponse {
|
|
@@ -234,6 +234,77 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
234
234
|
expiresAt: string;
|
|
235
235
|
user: User;
|
|
236
236
|
}>;
|
|
237
|
+
/**
|
|
238
|
+
* Refresh every device-local refresh-cookie slot in a single round trip
|
|
239
|
+
* (Google-style multi-account rebuild).
|
|
240
|
+
*
|
|
241
|
+
* Calls `POST {sessionBaseUrl}/auth/refresh-all` with `credentials: 'include'`
|
|
242
|
+
* and NO bearer. The browser attaches every `oxy_rt*` cookie it has; the
|
|
243
|
+
* server rotates each in parallel and returns one entry per VALID account.
|
|
244
|
+
*
|
|
245
|
+
* Failure handling:
|
|
246
|
+
* - 401 → no signed-in accounts on this device → returns `{ accounts: [] }`
|
|
247
|
+
* (NOT an error; this is the cold-boot "not signed in" path).
|
|
248
|
+
* - 404 → server is older than the multi-account endpoint. We fall back to
|
|
249
|
+
* `POST /auth/refresh` (single-slot) and wrap its response in the
|
|
250
|
+
* refresh-all shape so callers can treat the two paths uniformly. The
|
|
251
|
+
* fallback entry has `authuser: 0` (the legacy slot maps to slot 0 by
|
|
252
|
+
* convention) and a minimal `user` shape — consumers needing the full
|
|
253
|
+
* user must fetch it separately. Always exactly one account in this
|
|
254
|
+
* shape.
|
|
255
|
+
* - Any other non-2xx → throws via `handleError`.
|
|
256
|
+
*
|
|
257
|
+
* The refresh cookie itself never enters JS — only the rotated access
|
|
258
|
+
* tokens do. Each access token still needs to be planted via
|
|
259
|
+
* `setTokens(...)` (or per-account in-memory storage) at the consumer.
|
|
260
|
+
*/
|
|
261
|
+
refreshAllSessions(): Promise<RefreshAllResponse>;
|
|
262
|
+
/**
|
|
263
|
+
* Rotate a single refresh-cookie slot and return the fresh access token.
|
|
264
|
+
*
|
|
265
|
+
* When `authuser` is provided, the server rotates ONLY that slot
|
|
266
|
+
* (`oxy_rt_${authuser}`) — sibling accounts on the same device stay
|
|
267
|
+
* untouched. When omitted, the server picks the lowest indexed slot
|
|
268
|
+
* present (legacy fallback applies). The refresh cookie itself never
|
|
269
|
+
* enters JS.
|
|
270
|
+
*
|
|
271
|
+
* Returns `null` on 401 (no cookie / expired / reused) so the caller can
|
|
272
|
+
* fall through cleanly to the unauthenticated path.
|
|
273
|
+
*/
|
|
274
|
+
refreshTokenViaCookie(opts?: {
|
|
275
|
+
authuser?: number;
|
|
276
|
+
}): Promise<RefreshCookieResponse | null>;
|
|
277
|
+
/**
|
|
278
|
+
* Sign out a single device-local account by its authuser slot index.
|
|
279
|
+
*
|
|
280
|
+
* Revokes that slot's refresh-token family and deactivates its session;
|
|
281
|
+
* sibling indexed slots stay signed in. The browser-side `oxy_rt_${n}`
|
|
282
|
+
* cookie is cleared by the server's `Set-Cookie` response header.
|
|
283
|
+
*/
|
|
284
|
+
logoutSessionByAuthuser(authuser: number): Promise<void>;
|
|
285
|
+
/**
|
|
286
|
+
* Sign out EVERY device-local account on this device by clearing every
|
|
287
|
+
* presented refresh-cookie slot at once. Revokes every family + clears
|
|
288
|
+
* every slot. Always succeeds (idempotent on unknown/garbage tokens).
|
|
289
|
+
*/
|
|
290
|
+
logoutAllSessionsViaCookie(): Promise<void>;
|
|
291
|
+
/**
|
|
292
|
+
* Internal: raw `POST /auth/refresh[?authuser=N]` call returning the
|
|
293
|
+
* minted access token. Returns `null` on 401 / non-2xx. Used as both the
|
|
294
|
+
* implementation of `refreshTokenViaCookie` and the legacy fallback for
|
|
295
|
+
* `refreshAllSessions` against older servers.
|
|
296
|
+
*
|
|
297
|
+
* @internal
|
|
298
|
+
*/
|
|
299
|
+
_refreshCookieRaw(authuser?: number): Promise<RefreshCookieResponse | null>;
|
|
300
|
+
/**
|
|
301
|
+
* Internal: decode (without verifying) the `sessionId` claim from a
|
|
302
|
+
* server-signed access token. The server already verified the signature;
|
|
303
|
+
* the client only reads the claim to drive multi-session state.
|
|
304
|
+
*
|
|
305
|
+
* @internal
|
|
306
|
+
*/
|
|
307
|
+
_decodeSessionIdFromAccessToken(token: string): string | null;
|
|
237
308
|
/**
|
|
238
309
|
* Get sessions by session ID
|
|
239
310
|
*/
|
|
@@ -292,6 +363,7 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
292
363
|
__resetTokensForTests(): void;
|
|
293
364
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
294
365
|
getBaseURL(): string;
|
|
366
|
+
getSessionBaseUrl(): string;
|
|
295
367
|
getClient(): import("../HttpService").HttpService;
|
|
296
368
|
getMetrics(): {
|
|
297
369
|
totalRequests: number;
|
|
@@ -53,6 +53,7 @@ export declare function OxyServicesContactsMixin<T extends typeof OxyServicesBas
|
|
|
53
53
|
__resetTokensForTests(): void;
|
|
54
54
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
55
55
|
getBaseURL(): string;
|
|
56
|
+
getSessionBaseUrl(): string;
|
|
56
57
|
getClient(): import("../HttpService").HttpService;
|
|
57
58
|
getMetrics(): {
|
|
58
59
|
totalRequests: number;
|