@oxyhq/services 10.0.0 → 10.1.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/lib/commonjs/ui/components/SignInModal.js +12 -9
- package/lib/commonjs/ui/components/SignInModal.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +5 -1
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/screens/OxyAuthScreen.js +51 -20
- package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/commonjs/utils/deviceFlowSignIn.js +55 -0
- package/lib/commonjs/utils/deviceFlowSignIn.js.map +1 -0
- package/lib/module/ui/components/SignInModal.js +12 -9
- package/lib/module/ui/components/SignInModal.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +5 -1
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/screens/OxyAuthScreen.js +51 -20
- package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/module/utils/deviceFlowSignIn.js +51 -0
- package/lib/module/utils/deviceFlowSignIn.js.map +1 -0
- package/lib/typescript/commonjs/ui/components/SignInModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +1 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useServicesMutations.d.ts +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useServicesMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts +61 -0
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/SignInModal.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts +1 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useServicesMutations.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useServicesMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts.map +1 -1
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts +61 -0
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/ui/components/SignInModal.tsx +12 -9
- package/src/ui/context/OxyContext.tsx +8 -4
- package/src/ui/screens/OxyAuthScreen.tsx +52 -20
- package/src/utils/__tests__/deviceFlowSignIn.test.ts +104 -0
- package/src/utils/deviceFlowSignIn.ts +76 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared, pure orchestration for completing the cross-app device-flow sign-in
|
|
3
|
+
* (the QR-code / "Open Oxy Auth" path used on native and web).
|
|
4
|
+
*
|
|
5
|
+
* THE BUG THIS FIXES (native): once another authenticated device approves the
|
|
6
|
+
* pending AuthSession, the originating client is notified (socket / poll /
|
|
7
|
+
* deep-link) with the authorized `sessionId`. Before any session-management
|
|
8
|
+
* code can use it, the client MUST exchange the secret 128-bit `sessionToken`
|
|
9
|
+
* (held only by this client, generated for THIS flow) for the first access
|
|
10
|
+
* token via `claimSessionByToken` — the device-flow equivalent of OAuth's
|
|
11
|
+
* code-for-token exchange (RFC 8628 §3.4).
|
|
12
|
+
*
|
|
13
|
+
* Skipping the claim leaves the SDK with NO bearer token, so the subsequent
|
|
14
|
+
* `switchSession` -> `getTokenBySession` (`GET /session/token/:id`) call 401s
|
|
15
|
+
* against the C1-hardened API: the session is authorized server-side but the
|
|
16
|
+
* app never becomes authenticated and the UI sits "Waiting for
|
|
17
|
+
* authorization..." forever. The web `SignInModal` already claimed first; the
|
|
18
|
+
* native `OxyAuthScreen` did not. Consolidating the claim→switch sequence here
|
|
19
|
+
* keeps both paths identical and unit-testable, and prevents future drift.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { User } from '@oxyhq/core';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The minimal `OxyServices` surface this orchestration needs. Kept as a
|
|
26
|
+
* structural type (rather than importing the full client) so the helper is
|
|
27
|
+
* trivially unit-testable with a stub and never pulls the RN/Expo runtime into
|
|
28
|
+
* a test bundle.
|
|
29
|
+
*/
|
|
30
|
+
export interface DeviceFlowClient {
|
|
31
|
+
/**
|
|
32
|
+
* Exchange the device-flow `sessionToken` for the first access + refresh
|
|
33
|
+
* token, planting them on the client. Single-use; replay is rejected by the
|
|
34
|
+
* API. No bearer required — the high-entropy `sessionToken` IS the credential.
|
|
35
|
+
*/
|
|
36
|
+
claimSessionByToken: (sessionToken: string) => Promise<unknown>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface CompleteDeviceFlowSignInOptions {
|
|
40
|
+
/** The OxyServices client (or any object exposing `claimSessionByToken`). */
|
|
41
|
+
oxyServices: DeviceFlowClient;
|
|
42
|
+
/** The authorized device session id, delivered by the socket / poll / link. */
|
|
43
|
+
sessionId: string;
|
|
44
|
+
/**
|
|
45
|
+
* The secret `sessionToken` generated for THIS flow and registered via
|
|
46
|
+
* `POST /auth/session/create`. Required to claim the first access token.
|
|
47
|
+
*/
|
|
48
|
+
sessionToken: string;
|
|
49
|
+
/**
|
|
50
|
+
* The session-management `switchSession` from `useOxy()`. Hydrates the
|
|
51
|
+
* activated session (validates, fetches the user, persists, updates state).
|
|
52
|
+
* Runs AFTER the bearer is planted so its bearer-protected calls succeed.
|
|
53
|
+
*/
|
|
54
|
+
switchSession: (sessionId: string) => Promise<User>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Complete a device-flow sign-in: claim the first access token with the secret
|
|
59
|
+
* `sessionToken` (planting the bearer), then hydrate the session via
|
|
60
|
+
* `switchSession`. Returns the authenticated user.
|
|
61
|
+
*
|
|
62
|
+
* Throws if either the claim or the switch fails; callers surface a retry UI.
|
|
63
|
+
*/
|
|
64
|
+
export async function completeDeviceFlowSignIn({
|
|
65
|
+
oxyServices,
|
|
66
|
+
sessionId,
|
|
67
|
+
sessionToken,
|
|
68
|
+
switchSession,
|
|
69
|
+
}: CompleteDeviceFlowSignInOptions): Promise<User> {
|
|
70
|
+
// 1) Plant the bearer + refresh tokens. Without this the bearer-protected
|
|
71
|
+
// `getTokenBySession` inside `switchSession` 401s (the native regression).
|
|
72
|
+
await oxyServices.claimSessionByToken(sessionToken);
|
|
73
|
+
|
|
74
|
+
// 2) Bearer is now planted — hydrate the session through the normal path.
|
|
75
|
+
return switchSession(sessionId);
|
|
76
|
+
}
|