@smarthivelabs-devs/auth-expo 1.0.0 → 1.2.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 CHANGED
@@ -1,6 +1,13 @@
1
1
  # @smarthivelabs-devs/auth-expo
2
2
 
3
- SmartHive Auth for React Native and Expo. Provides a provider, hooks, and components with SecureStore-backed token storage and deep-link OAuth support.
3
+ SmartHive Auth for React Native and Expo. Provides a provider, hooks, and components with SecureStore-backed token storage.
4
+
5
+ Supports two sign-in modes — both in the same package, zero config difference:
6
+
7
+ | Mode | How it works | Good for |
8
+ |---|---|---|
9
+ | **Headless** | Call `signIn.*` directly — no browser, custom UI | Native mobile apps with branded login screens |
10
+ | **OAuth redirect** | `login()` opens system browser, deep-links back | Social login, SSO, or when you want the hosted UI |
4
11
 
5
12
  ---
6
13
 
@@ -10,303 +17,351 @@ SmartHive Auth for React Native and Expo. Provides a provider, hooks, and compon
10
17
  npx expo install @smarthivelabs-devs/auth-expo @smarthivelabs-devs/auth-sdk expo-auth-session expo-secure-store
11
18
  ```
12
19
 
13
- Or with npm/pnpm (non-Expo managed workflow):
14
-
15
20
  ```bash
21
+ # npm / pnpm
16
22
  npm install @smarthivelabs-devs/auth-expo @smarthivelabs-devs/auth-sdk expo-auth-session expo-secure-store
17
23
  pnpm add @smarthivelabs-devs/auth-expo @smarthivelabs-devs/auth-sdk expo-auth-session expo-secure-store
18
24
  ```
19
25
 
20
- > **Peer dependencies required:** `expo-auth-session>=5`, `expo-secure-store>=12`, `react>=18`, `react-native>=0.73`
21
-
22
- ---
23
-
24
- ## Prerequisites
25
-
26
- 1. A SmartHive Auth project — grab `projectId`, `publishableKey`, and `baseUrl` from your dashboard.
27
- 2. A registered deep link scheme for your Expo app (see below).
28
-
29
- ---
30
-
31
- ## Deep Link Setup
32
-
33
- SmartHive Auth uses OAuth 2.0 + PKCE. After login, the server redirects back to your app via a deep link (e.g. `myapp://auth/callback`). You must register a custom scheme in `app.json`:
34
-
35
- ```json
36
- // app.json
37
- {
38
- "expo": {
39
- "scheme": "myapp",
40
- "android": {
41
- "intentFilters": [
42
- {
43
- "action": "VIEW",
44
- "autoVerify": true,
45
- "data": [{ "scheme": "myapp" }],
46
- "category": ["BROWSABLE", "DEFAULT"]
47
- }
48
- ]
49
- }
50
- }
51
- }
52
- ```
53
-
54
- Rebuild your native app after this change:
55
-
56
- ```bash
57
- npx expo prebuild
58
- ```
26
+ > **Peer dependencies:** `expo-auth-session>=5`, `expo-secure-store>=12`, `react>=18`, `react-native>=0.73`
59
27
 
60
28
  ---
61
29
 
62
30
  ## Setup
63
31
 
64
- Wrap your root component with `SmartHiveProvider`. Use `buildRedirectUri` to construct the deep link URI from your scheme.
32
+ Wrap your root component with `SmartHiveProvider`. The `redirectUri` is only needed for the OAuth redirect flow you can still set it even if you only use headless.
65
33
 
66
34
  ```tsx
67
- // App.tsx
35
+ // app/_layout.tsx
68
36
  import { SmartHiveProvider, buildRedirectUri } from "@smarthivelabs-devs/auth-expo";
69
37
 
70
- const REDIRECT_URI = buildRedirectUri("myapp"); // → "myapp://auth/callback"
71
-
72
- export default function App() {
38
+ export default function Layout() {
73
39
  return (
74
40
  <SmartHiveProvider
75
41
  projectId={process.env.EXPO_PUBLIC_AUTH_PROJECT_ID!}
76
42
  publishableKey={process.env.EXPO_PUBLIC_AUTH_PUBLISHABLE_KEY!}
77
43
  baseUrl={process.env.EXPO_PUBLIC_AUTH_BASE_URL!}
78
- redirectUri={REDIRECT_URI}
44
+ redirectUri={buildRedirectUri("myapp")}
79
45
  >
80
- <RootNavigator />
46
+ <Stack />
81
47
  </SmartHiveProvider>
82
48
  );
83
49
  }
84
50
  ```
85
51
 
86
- ### `buildRedirectUri(scheme, path?)`
87
-
88
- Helper that constructs a deep link URI:
89
-
90
- ```ts
91
- buildRedirectUri("myapp") // → "myapp://auth/callback"
92
- buildRedirectUri("myapp", "auth/done") // → "myapp://auth/done"
52
+ ```bash
53
+ # .env
54
+ EXPO_PUBLIC_AUTH_PROJECT_ID=proj_abc123
55
+ EXPO_PUBLIC_AUTH_PUBLISHABLE_KEY=pk_prod_abc123
56
+ EXPO_PUBLIC_AUTH_BASE_URL=https://auth.myapp.com
93
57
  ```
94
58
 
95
59
  ---
96
60
 
97
- ## Provider Props
61
+ ## Headless Sign-in (Custom Login Screen)
98
62
 
99
- | Prop | Type | Required | Description |
100
- |---|---|---|---|
101
- | `projectId` | `string` | Yes | Your SmartHive project ID |
102
- | `publishableKey` | `string` | Yes | Your publishable key |
103
- | `baseUrl` | `string` | Yes | URL of your SmartHive Auth service |
104
- | `redirectUri` | `string` | Yes | Deep link callback URI (e.g. `myapp://auth/callback`) |
105
- | `authDomain` | `string` | No | Custom branded auth domain |
106
- | `children` | `ReactNode` | Yes | Your app tree |
63
+ No browser, no redirect. Call the method, get tokens. Full control of your UI.
107
64
 
108
- ---
65
+ ### Email + Password
109
66
 
110
- ## How OAuth Works in Expo
111
-
112
- 1. User taps **Sign in** → `login()` is called
113
- 2. The SDK builds the OAuth URL with PKCE, saves the verifier in SecureStore, and opens the URL in the system browser via `Linking.openURL()`
114
- 3. The user logs in via the browser
115
- 4. The server redirects to `myapp://auth/callback?code=...&state=...`
116
- 5. `Linking` fires a `url` event — `SmartHiveProvider` handles it automatically, exchanges the code for tokens, and updates the session state
117
-
118
- No manual callback handling is needed — the provider sets up the `Linking` event listener internally.
119
-
120
- ---
67
+ ```tsx
68
+ import { useAuth } from "@smarthivelabs-devs/auth-expo";
69
+ import { useState } from "react";
70
+ import { Button, TextInput, View, Text } from "react-native";
121
71
 
122
- ## Hooks
72
+ export default function LoginScreen() {
73
+ const { signIn } = useAuth();
74
+ const [email, setEmail] = useState("");
75
+ const [password, setPassword] = useState("");
76
+ const [error, setError] = useState("");
77
+
78
+ async function handleSignIn() {
79
+ try {
80
+ await signIn.email({ email, password });
81
+ // Session is saved automatically — user is now signed in
82
+ } catch (e: any) {
83
+ setError(e.message);
84
+ }
85
+ }
123
86
 
124
- ### `useAuth()`
87
+ return (
88
+ <View>
89
+ <TextInput value={email} onChangeText={setEmail} placeholder="Email" />
90
+ <TextInput value={password} onChangeText={setPassword} placeholder="Password" secureTextEntry />
91
+ {error ? <Text>{error}</Text> : null}
92
+ <Button title="Sign in" onPress={handleSignIn} />
93
+ </View>
94
+ );
95
+ }
96
+ ```
125
97
 
126
- Returns the full auth context.
98
+ ### Phone OTP
127
99
 
128
100
  ```tsx
129
101
  import { useAuth } from "@smarthivelabs-devs/auth-expo";
102
+ import { useState } from "react";
103
+ import { Button, TextInput, View } from "react-native";
104
+
105
+ export default function PhoneLoginScreen() {
106
+ const { signIn } = useAuth();
107
+ const [phone, setPhone] = useState("");
108
+ const [code, setCode] = useState("");
109
+ const [step, setStep] = useState<"phone" | "code">("phone");
110
+
111
+ async function sendOtp() {
112
+ await signIn.phone.sendOtp({ phoneNumber: phone });
113
+ setStep("code");
114
+ }
115
+
116
+ async function verifyOtp() {
117
+ await signIn.phone.verify({ phoneNumber: phone, code });
118
+ // Signed in — session saved automatically
119
+ }
120
+
121
+ if (step === "phone") {
122
+ return (
123
+ <View>
124
+ <TextInput value={phone} onChangeText={setPhone} placeholder="+1234567890" keyboardType="phone-pad" />
125
+ <Button title="Send code" onPress={sendOtp} />
126
+ </View>
127
+ );
128
+ }
130
129
 
131
- function HomeScreen() {
132
- const {
133
- session, // AuthSession | null
134
- isLoaded, // true once initial SecureStore read is done
135
- isSignedIn, // boolean
136
- login, // (options?) => Promise<void>
137
- logout, // () => Promise<void>
138
- refreshSession, // () => Promise<void>
139
- authFetch, // authenticated fetch wrapper
140
- } = useAuth();
141
-
142
- if (!isLoaded) return <ActivityIndicator />;
143
-
144
- return isSignedIn ? (
145
- <Button title="Sign out" onPress={logout} />
146
- ) : (
147
- <Button title="Sign in" onPress={() => login()} />
130
+ return (
131
+ <View>
132
+ <TextInput value={code} onChangeText={setCode} placeholder="Enter code" keyboardType="number-pad" />
133
+ <Button title="Verify" onPress={verifyOtp} />
134
+ </View>
148
135
  );
149
136
  }
150
137
  ```
151
138
 
152
- ---
139
+ ### Email OTP
153
140
 
154
- ### `useSession()`
141
+ ```tsx
142
+ const { signIn } = useAuth();
143
+
144
+ // Step 1 — send the code
145
+ await signIn.emailOtp.send({ email: "user@example.com" });
146
+
147
+ // Step 2 — verify (returns session, user is now signed in)
148
+ await signIn.emailOtp.verify({ email: "user@example.com", code: "123456" });
149
+ ```
155
150
 
156
- Returns the current `AuthSession` or `null`.
151
+ ### Magic Link
157
152
 
158
153
  ```tsx
159
- import { useSession } from "@smarthivelabs-devs/auth-expo";
154
+ const { signIn } = useAuth();
160
155
 
161
- function TokenScreen() {
162
- const session = useSession();
163
- if (!session) return <Text>Not signed in</Text>;
164
- return <Text selectable>{session.accessToken}</Text>;
165
- }
156
+ // Sends an email — user clicks the link to sign in (no token returned here)
157
+ await signIn.magicLink.send({ email: "user@example.com" });
166
158
  ```
167
159
 
168
160
  ---
169
161
 
170
- ### `useUser()`
171
-
172
- Returns the user object from the session, or `null`.
162
+ ## Headless Sign-up
173
163
 
174
164
  ```tsx
175
- import { useUser } from "@smarthivelabs-devs/auth-expo";
165
+ import { useAuth } from "@smarthivelabs-devs/auth-expo";
166
+
167
+ const { signUp } = useAuth();
168
+
169
+ const result = await signUp.email({
170
+ email: "user@example.com",
171
+ password: "secret123",
172
+ name: "Jane Doe", // optional
173
+ });
176
174
 
177
- function ProfileScreen() {
178
- const user = useUser();
179
- if (!user) return null;
180
- return <Text>Welcome, {(user as any).email}</Text>;
175
+ if (result.requiresVerification) {
176
+ // Email verification required — show "check your inbox" screen
177
+ // No session yet, tokens are empty
178
+ } else {
179
+ // Account created and signed in immediately
181
180
  }
182
181
  ```
183
182
 
184
183
  ---
185
184
 
186
- ### `useIsLoaded()`
185
+ ## Social OAuth Sign-in (Google, Apple, GitHub, etc.)
187
186
 
188
- Returns `true` once the initial SecureStore session check is done. Prevents a flash of the signed-out state on app startup.
187
+ Each social provider uses **your project's own credentials** — the consent screen shows your app name. Configure credentials in your SmartHive dashboard under **Project OAuth Providers**, then call:
189
188
 
190
189
  ```tsx
191
- import { useIsLoaded } from "@smarthivelabs-devs/auth-expo";
190
+ import { useAuth } from "@smarthivelabs-devs/auth-expo";
191
+ import { Button } from "react-native";
192
+
193
+ export default function LoginScreen() {
194
+ const { signIn } = useAuth();
192
195
 
193
- function RootNavigator() {
194
- const isLoaded = useIsLoaded();
195
- if (!isLoaded) return <SplashScreen />;
196
- return <AppNavigator />;
196
+ return (
197
+ <>
198
+ <Button title="Continue with Google" onPress={() => signIn.social("google")} />
199
+ <Button title="Continue with Apple" onPress={() => signIn.social("apple")} />
200
+ <Button title="Continue with GitHub" onPress={() => signIn.social("github")} />
201
+ </>
202
+ );
197
203
  }
198
204
  ```
199
205
 
206
+ `signIn.social()` calls `Linking.openURL()` to open the provider's consent screen in the system browser. When the user approves, the provider redirects back to your app's `redirectUri` deep link with `?access_token=...&refresh_token=...`. The `SmartHiveProvider` deep link listener picks this up automatically and saves the session — no extra setup needed.
207
+
208
+ **Supported providers:**
209
+ `google` · `apple` · `github` · `facebook` · `twitter` · `linkedin` · `microsoft` · `discord` · `spotify` · `twitch` · `reddit` · `gitlab` · `slack` · `notion` · `zoom` · `figma`
210
+
211
+ > **Deep link required** — make sure `redirectUri` is set to your app scheme (e.g. `myapp://auth/callback`) and your scheme is registered in `app.json`. See the Deep Link Setup section below.
212
+
200
213
  ---
201
214
 
202
- ### `useIsSignedIn()`
215
+ ## OAuth Redirect Sign-in (SmartHive hosted page)
203
216
 
204
- Returns `true` (signed in), `false` (signed out), or `null` (still loading).
217
+ The original PKCE flow redirects to the SmartHive hosted login page and back. Use it for SSO or when you want the hosted login UI.
205
218
 
206
219
  ```tsx
207
- import { useIsSignedIn } from "@smarthivelabs-devs/auth-expo";
220
+ import { useAuth } from "@smarthivelabs-devs/auth-expo";
221
+ import { Button } from "react-native";
222
+
223
+ export default function LoginScreen() {
224
+ const { login } = useAuth();
225
+ return <Button title="Sign in with SmartHive" onPress={() => login()} />;
226
+ }
227
+ ```
208
228
 
209
- function AuthGate({ children }: { children: React.ReactNode }) {
210
- const isSignedIn = useIsSignedIn();
211
- const router = useRouter();
229
+ ### Deep Link Setup (required for OAuth redirect only)
212
230
 
213
- useEffect(() => {
214
- if (isSignedIn === false) router.replace("/login");
215
- }, [isSignedIn]);
231
+ If you use `login()`, register a custom scheme in `app.json` so the browser can redirect back:
216
232
 
217
- if (isSignedIn === null) return <ActivityIndicator />;
218
- if (!isSignedIn) return null;
219
- return <>{children}</>;
233
+ ```json
234
+ {
235
+ "expo": {
236
+ "scheme": "myapp",
237
+ "android": {
238
+ "intentFilters": [
239
+ {
240
+ "action": "VIEW",
241
+ "autoVerify": true,
242
+ "data": [{ "scheme": "myapp" }],
243
+ "category": ["BROWSABLE", "DEFAULT"]
244
+ }
245
+ ]
246
+ }
247
+ }
220
248
  }
221
249
  ```
222
250
 
223
- ---
251
+ Rebuild after changing `app.json`:
224
252
 
225
- ### `useAuthFetch()`
253
+ ```bash
254
+ npx expo prebuild
255
+ ```
226
256
 
227
- Returns an authenticated `fetch` function. Automatically injects the Bearer token on every request — tokens are refreshed transparently.
257
+ No extra setup needed for headless sign-in it works without a deep link.
228
258
 
229
- ```tsx
230
- import { useAuthFetch } from "@smarthivelabs-devs/auth-expo";
259
+ ---
231
260
 
232
- function DataScreen() {
233
- const authFetch = useAuthFetch();
234
- const [data, setData] = useState(null);
261
+ ## Sign-out
235
262
 
236
- async function load() {
237
- const res = await authFetch("https://api.myapp.com/protected");
238
- setData(await res.json());
239
- }
263
+ ```tsx
264
+ const { logout } = useAuth();
240
265
 
241
- return (
242
- <View>
243
- <Button title="Load data" onPress={load} />
244
- {data && <Text>{JSON.stringify(data)}</Text>}
245
- </View>
246
- );
247
- }
266
+ // Clears SecureStore + invalidates session on the server
267
+ await logout();
248
268
  ```
249
269
 
250
270
  ---
251
271
 
252
- ### `useAuthorizationHeader()`
272
+ ## Hooks
273
+
274
+ ### `useAuth()`
253
275
 
254
- Returns a function that resolves to `{ authorization: "Bearer <token>" }`. Useful for passing to SDKs or GraphQL clients.
276
+ Returns the full auth context.
255
277
 
256
278
  ```tsx
257
- import { useAuthorizationHeader } from "@smarthivelabs-devs/auth-expo";
279
+ const {
280
+ session, // AuthSession | null
281
+ isLoaded, // true once initial SecureStore read is done
282
+ isSignedIn, // boolean
283
+ login, // OAuth redirect sign-in (PKCE, SmartHive hosted page)
284
+ logout, // sign out
285
+ signIn, // headless + social sign-in methods
286
+ signUp, // headless sign-up methods
287
+ refreshSession, // force a token refresh
288
+ authFetch, // authenticated fetch wrapper
289
+ getAuthorizationHeader, // () => Promise<{ authorization: string }>
290
+ } = useAuth();
291
+
292
+ // Social sign-in is under signIn.social:
293
+ await signIn.social("google");
294
+ await signIn.social("apple");
295
+ await signIn.social("github");
296
+ ```
297
+
298
+ ### `useSession()`
258
299
 
259
- function ApolloSetup() {
260
- const getAuthorizationHeader = useAuthorizationHeader();
300
+ ```tsx
301
+ const session = useSession(); // AuthSession | null
302
+ // session.accessToken, session.refreshToken, session.expiresAt, session.user
303
+ ```
261
304
 
262
- const authLink = new ApolloLink(async (operation, forward) => {
263
- const headers = await getAuthorizationHeader();
264
- operation.setContext({ headers });
265
- return forward(operation);
266
- });
305
+ ### `useUser()`
267
306
 
268
- // ...
269
- }
307
+ ```tsx
308
+ const user = useUser(); // unknown | null
270
309
  ```
271
310
 
272
- ---
311
+ ### `useIsLoaded()`
273
312
 
274
- ## Render Helpers
313
+ `true` once the initial SecureStore check is complete. Use this to avoid a flash of unauthenticated state on startup.
275
314
 
276
- ### `<SignedIn>`
315
+ ```tsx
316
+ const isLoaded = useIsLoaded();
317
+ if (!isLoaded) return <SplashScreen />;
318
+ ```
277
319
 
278
- Renders children only when auth has loaded **and** a session exists.
320
+ ### `useIsSignedIn()`
321
+
322
+ Returns `true` (signed in), `false` (signed out), or `null` (still loading).
279
323
 
280
324
  ```tsx
281
- import { SignedIn } from "@smarthivelabs-devs/auth-expo";
325
+ const isSignedIn = useIsSignedIn();
282
326
 
283
- <SignedIn>
284
- <UserDashboard />
285
- </SignedIn>
327
+ useEffect(() => {
328
+ if (isSignedIn === false) router.replace("/login");
329
+ }, [isSignedIn]);
286
330
  ```
287
331
 
288
- ### `<SignedOut>`
332
+ ### `useAuthFetch()`
289
333
 
290
- Renders children only when auth has loaded **and** there is no session.
334
+ Authenticated `fetch` wrapper. Bearer token is injected automatically and refreshed transparently when near expiry.
291
335
 
292
336
  ```tsx
293
- import { SignedOut } from "@smarthivelabs-devs/auth-expo";
337
+ const authFetch = useAuthFetch();
338
+ const res = await authFetch("https://api.myapp.com/protected");
339
+ ```
294
340
 
295
- <SignedOut>
296
- <LandingScreen />
297
- </SignedOut>
341
+ ### `useAuthorizationHeader()`
342
+
343
+ Resolves to `{ authorization: "Bearer <token>" }`. Useful for GraphQL clients or custom SDK setup.
344
+
345
+ ```tsx
346
+ const getAuthorizationHeader = useAuthorizationHeader();
347
+ const headers = await getAuthorizationHeader();
298
348
  ```
299
349
 
300
- ### `<AuthLoading>`
350
+ ---
301
351
 
302
- Renders children while the initial session check is running.
352
+ ## Render Helpers
303
353
 
304
354
  ```tsx
305
- import { AuthLoading } from "@smarthivelabs-devs/auth-expo";
355
+ import { SignedIn, SignedOut, AuthLoading } from "@smarthivelabs-devs/auth-expo";
356
+
357
+ // Shown only when loaded + authenticated
358
+ <SignedIn><Dashboard /></SignedIn>
306
359
 
307
- <AuthLoading>
308
- <ActivityIndicator size="large" />
309
- </AuthLoading>
360
+ // Shown only when loaded + not authenticated
361
+ <SignedOut><LoginScreen /></SignedOut>
362
+
363
+ // Shown while the initial SecureStore check is running
364
+ <AuthLoading><ActivityIndicator /></AuthLoading>
310
365
  ```
311
366
 
312
367
  ---
@@ -315,11 +370,11 @@ import { AuthLoading } from "@smarthivelabs-devs/auth-expo";
315
370
 
316
371
  ```
317
372
  app/
318
- ├── _layout.tsx ← SmartHiveProvider here
319
- ├── index.tsx ← SignedIn / SignedOut
320
- ├── login.tsx ← login screen
373
+ ├── _layout.tsx ← SmartHiveProvider here
374
+ ├── index.tsx ← SignedIn / SignedOut routing
375
+ ├── login.tsx your custom login screen using signIn.*
321
376
  └── (protected)/
322
- └── dashboard.tsx ← authenticated screen
377
+ └── dashboard.tsx
323
378
  ```
324
379
 
325
380
  ```tsx
@@ -359,85 +414,70 @@ export default function Index() {
359
414
  ```
360
415
 
361
416
  ```tsx
362
- // app/login.tsx
417
+ // app/login.tsx — custom screen, no browser redirect
363
418
  import { useAuth } from "@smarthivelabs-devs/auth-expo";
364
- import { Button, View } from "react-native";
419
+ import { useState } from "react";
420
+ import { Button, TextInput, View, Text, StyleSheet } from "react-native";
365
421
 
366
422
  export default function LoginScreen() {
367
- const { login } = useAuth();
368
- return (
369
- <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
370
- <Button title="Sign in with SmartHive" onPress={() => login()} />
371
- </View>
372
- );
373
- }
374
- ```
375
-
376
- ```tsx
377
- // app/(protected)/dashboard.tsx
378
- import { useAuth, SignedIn } from "@smarthivelabs-devs/auth-expo";
379
- import { Button, Text, View } from "react-native";
380
-
381
- export default function Dashboard() {
382
- const { logout, authFetch } = useAuth();
423
+ const { signIn } = useAuth();
424
+ const [email, setEmail] = useState("");
425
+ const [password, setPassword] = useState("");
426
+ const [loading, setLoading] = useState(false);
427
+ const [error, setError] = useState("");
428
+
429
+ async function handleSignIn() {
430
+ setLoading(true);
431
+ setError("");
432
+ try {
433
+ await signIn.email({ email, password });
434
+ } catch (e: any) {
435
+ setError(e.message ?? "Sign in failed.");
436
+ } finally {
437
+ setLoading(false);
438
+ }
439
+ }
383
440
 
384
441
  return (
385
- <SignedIn>
386
- <View>
387
- <Text>Dashboard</Text>
388
- <Button title="Sign out" onPress={logout} />
389
- </View>
390
- </SignedIn>
442
+ <View style={styles.container}>
443
+ <TextInput style={styles.input} value={email} onChangeText={setEmail} placeholder="Email" autoCapitalize="none" />
444
+ <TextInput style={styles.input} value={password} onChangeText={setPassword} placeholder="Password" secureTextEntry />
445
+ {error ? <Text style={styles.error}>{error}</Text> : null}
446
+ <Button title={loading ? "Signing in…" : "Sign in"} onPress={handleSignIn} disabled={loading} />
447
+ </View>
391
448
  );
392
449
  }
393
- ```
394
-
395
- ---
396
-
397
- ## Low-level: `initExpoAuth`
398
-
399
- If you need the client directly without the provider (advanced use), use `initExpoAuth`:
400
-
401
- ```ts
402
- import { initExpoAuth, buildRedirectUri } from "@smarthivelabs-devs/auth-expo";
403
450
 
404
- const client = initExpoAuth({
405
- projectId: "proj_abc123",
406
- publishableKey: "pk_live_abc123",
407
- baseUrl: "https://auth.myapp.com",
408
- redirectUri: buildRedirectUri("myapp"),
451
+ const styles = StyleSheet.create({
452
+ container: { flex: 1, justifyContent: "center", padding: 24 },
453
+ input: { borderWidth: 1, borderColor: "#ccc", borderRadius: 8, padding: 12, marginBottom: 12 },
454
+ error: { color: "red", marginBottom: 12 },
409
455
  });
410
-
411
- await client.initialize();
412
-
413
- // The client behaves the same as SmartHiveAuthClient from auth-sdk,
414
- // but uses SecureStore and Linking instead of localStorage + location.assign
415
456
  ```
416
457
 
417
458
  ---
418
459
 
419
- ## Environment Variables
460
+ ## Token Storage
420
461
 
421
- With Expo's built-in env support (SDK 49+):
462
+ All tokens are stored in `expo-secure-store`:
422
463
 
423
- ```bash
424
- # .env
425
- EXPO_PUBLIC_AUTH_PROJECT_ID=proj_abc123
426
- EXPO_PUBLIC_AUTH_PUBLISHABLE_KEY=pk_live_abc123
427
- EXPO_PUBLIC_AUTH_BASE_URL=https://auth.myapp.com
428
- ```
464
+ - **iOS**: Keychain Services
465
+ - **Android**: Android Keystore (AES encryption)
429
466
 
430
- > Variables prefixed `EXPO_PUBLIC_` are embedded in the app bundle at build time.
467
+ PKCE verifier and state (used during OAuth redirect flow) are also stored in SecureStore and deleted after the code exchange completes.
431
468
 
432
469
  ---
433
470
 
434
- ## Token Storage
435
-
436
- Tokens are stored in `expo-secure-store`, which uses:
437
- - **iOS**: Keychain Services
438
- - **Android**: Keystore System (Android Keystore-backed AES encryption)
471
+ ## Provider Props
439
472
 
440
- PKCE verifier and state are also stored in SecureStore during the login flow and deleted after the code exchange.
473
+ | Prop | Type | Required | Description |
474
+ |---|---|---|---|
475
+ | `projectId` | `string` | Yes | Your SmartHive project ID |
476
+ | `publishableKey` | `string` | Yes | Your publishable key (`pk_prod_*`) |
477
+ | `baseUrl` | `string` | Yes | URL of your SmartHive Auth service |
478
+ | `redirectUri` | `string` | Yes | Deep link callback URI — used only for OAuth redirect flow |
479
+ | `authDomain` | `string` | No | Custom branded auth domain |
480
+ | `children` | `ReactNode` | Yes | Your app tree |
441
481
 
442
482
  ---
443
483
 
@@ -451,12 +491,40 @@ import type {
451
491
 
452
492
  import type {
453
493
  AuthSession,
494
+ HeadlessClient,
495
+ HeadlessSignInResult,
496
+ HeadlessSignUpResult,
454
497
  SmartHiveAuthClient,
455
498
  } from "@smarthivelabs-devs/auth-sdk";
456
499
  ```
457
500
 
458
501
  ---
459
502
 
503
+ ## Low-level: `initExpoAuth`
504
+
505
+ Direct client without the provider (advanced use):
506
+
507
+ ```ts
508
+ import { initExpoAuth, buildRedirectUri } from "@smarthivelabs-devs/auth-expo";
509
+
510
+ const client = initExpoAuth({
511
+ projectId: "proj_abc123",
512
+ publishableKey: "pk_prod_abc123",
513
+ baseUrl: "https://auth.myapp.com",
514
+ redirectUri: buildRedirectUri("myapp"),
515
+ });
516
+
517
+ await client.initialize();
518
+
519
+ // Headless sign-in
520
+ const session = await client.headless.signIn.email({ email, password });
521
+
522
+ // OAuth redirect
523
+ await client.login();
524
+ ```
525
+
526
+ ---
527
+
460
528
  ## Related Packages
461
529
 
462
530
  | Package | Use case |
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { SmartHiveAuthConfig, SmartHiveAuthClient, AuthSession } from '@smarthivelabs-devs/auth-sdk';
2
+ import { SmartHiveAuthConfig, SmartHiveAuthClient, AuthSession, HeadlessSignInResult, SocialProvider, HeadlessSignUpResult } from '@smarthivelabs-devs/auth-sdk';
3
3
 
4
4
  interface SmartHiveExpoConfig extends Omit<SmartHiveAuthConfig, "storage"> {
5
5
  /** Deep link redirect URI, e.g. "myapp://auth/callback" */
@@ -20,6 +20,7 @@ interface AuthContextValue {
20
20
  session: AuthSession | null;
21
21
  isLoaded: boolean;
22
22
  isSignedIn: boolean;
23
+ /** OAuth 2.0 + PKCE browser redirect sign-in (unchanged). */
23
24
  login(options?: {
24
25
  redirectUri?: string;
25
26
  }): Promise<void>;
@@ -27,23 +28,60 @@ interface AuthContextValue {
27
28
  refreshSession(): Promise<void>;
28
29
  getAuthorizationHeader(): Promise<Record<string, string>>;
29
30
  authFetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
31
+ /**
32
+ * Headless (no browser) sign-in methods for custom login screens.
33
+ * Tokens are stored in SecureStore automatically on success.
34
+ */
35
+ signIn: {
36
+ email(params: {
37
+ email: string;
38
+ password: string;
39
+ }): Promise<HeadlessSignInResult>;
40
+ phone: {
41
+ sendOtp(params: {
42
+ phoneNumber: string;
43
+ }): Promise<void>;
44
+ verify(params: {
45
+ phoneNumber: string;
46
+ code: string;
47
+ }): Promise<HeadlessSignInResult>;
48
+ };
49
+ emailOtp: {
50
+ send(params: {
51
+ email: string;
52
+ }): Promise<void>;
53
+ verify(params: {
54
+ email: string;
55
+ code: string;
56
+ }): Promise<HeadlessSignInResult>;
57
+ };
58
+ magicLink: {
59
+ send(params: {
60
+ email: string;
61
+ callbackURL?: string;
62
+ }): Promise<void>;
63
+ };
64
+ /** Initiate a social OAuth flow — opens the provider's consent screen via Linking. */
65
+ social(provider: SocialProvider, options?: {
66
+ redirectUri?: string;
67
+ }): Promise<void>;
68
+ };
69
+ signUp: {
70
+ email(params: {
71
+ email: string;
72
+ password: string;
73
+ name?: string;
74
+ }): Promise<HeadlessSignUpResult>;
75
+ };
30
76
  }
31
77
  interface SmartHiveProviderProps extends SmartHiveExpoConfig {
32
78
  children: React.ReactNode;
33
79
  }
34
80
  /**
35
81
  * Wraps your Expo app and provides auth state to all child components.
36
- * Tokens are stored in SecureStore. OAuth is handled via deep links.
37
- *
38
- * @example
39
- * <SmartHiveProvider
40
- * projectId="proj_..."
41
- * publishableKey="pk_..."
42
- * baseUrl="https://authcore.smarthivelabs.dev/prod"
43
- * redirectUri="myapp://auth/callback"
44
- * >
45
- * <App />
46
- * </SmartHiveProvider>
82
+ * Tokens are stored in SecureStore. Supports both:
83
+ * - OAuth 2.0 + PKCE browser redirect via `login()`
84
+ * - Headless direct sign-in via `signIn.*` (no browser, custom login screens)
47
85
  */
48
86
  declare function SmartHiveProvider({ children, ...config }: SmartHiveProviderProps): react_jsx_runtime.JSX.Element;
49
87
  declare function useAuth(): AuthContextValue;
package/dist/index.js CHANGED
@@ -12,7 +12,8 @@ import { Linking } from "react-native";
12
12
  import { AuthRequest } from "expo-auth-session";
13
13
  import * as SecureStore from "expo-secure-store";
14
14
  import {
15
- initAuth
15
+ initAuth,
16
+ envFromPublishableKey
16
17
  } from "@smarthivelabs-devs/auth-sdk";
17
18
  import { Fragment, jsx } from "react/jsx-runtime";
18
19
  var secureStorage = {
@@ -60,6 +61,15 @@ function initExpoAuth(config) {
60
61
  }
61
62
  await secureStorage.setItem(storageKeys.pkceState, request.state);
62
63
  await Linking.openURL(url);
64
+ },
65
+ async loginSocial(provider, options) {
66
+ const redirectUri = options?.redirectUri ?? config.redirectUri;
67
+ const authBase = normalizeBaseUrl(config.authDomain ?? config.baseUrl);
68
+ const env = envFromPublishableKey(config.publishableKey);
69
+ const url = new URL(`${authBase}/${env}/api/auth/social/${provider}`);
70
+ url.searchParams.set("project_id", config.projectId);
71
+ url.searchParams.set("redirect_uri", redirectUri);
72
+ await Linking.openURL(url.toString());
63
73
  }
64
74
  };
65
75
  }
@@ -83,8 +93,17 @@ function SmartHiveProvider({ children, ...config }) {
83
93
  }, [client]);
84
94
  useEffect(() => {
85
95
  function handleUrl({ url }) {
86
- client.handleCallback({ url }).then((s) => setSession(s)).catch(() => {
87
- });
96
+ try {
97
+ const parsed = new URL(url);
98
+ if (parsed.searchParams.has("access_token") || parsed.searchParams.has("error")) {
99
+ client.handleSocialCallback({ url }).then((s) => setSession(s)).catch(() => {
100
+ });
101
+ } else {
102
+ client.handleCallback({ url }).then((s) => setSession(s)).catch(() => {
103
+ });
104
+ }
105
+ } catch {
106
+ }
88
107
  }
89
108
  const sub = Linking.addEventListener("url", handleUrl);
90
109
  Linking.getInitialURL().then((url) => {
@@ -111,6 +130,53 @@ function SmartHiveProvider({ children, ...config }) {
111
130
  (input, init) => client.fetch(input, init),
112
131
  [client]
113
132
  );
133
+ function wrapHeadlessSignIn(fn) {
134
+ return async (params) => {
135
+ const result = await fn(params);
136
+ setSession({
137
+ accessToken: result.accessToken,
138
+ refreshToken: result.refreshToken,
139
+ expiresAt: result.expiresAt,
140
+ user: result.user
141
+ });
142
+ return result;
143
+ };
144
+ }
145
+ const signIn = useMemo(() => {
146
+ const h = client.headless;
147
+ return {
148
+ email: wrapHeadlessSignIn(h.signIn.email.bind(h.signIn)),
149
+ phone: {
150
+ sendOtp: (p) => h.signIn.phone.sendOtp(p),
151
+ verify: wrapHeadlessSignIn(h.signIn.phone.verify.bind(h.signIn.phone))
152
+ },
153
+ emailOtp: {
154
+ send: (p) => h.signIn.emailOtp.send(p),
155
+ verify: wrapHeadlessSignIn(h.signIn.emailOtp.verify.bind(h.signIn.emailOtp))
156
+ },
157
+ magicLink: {
158
+ send: (p) => h.signIn.magicLink.send(p)
159
+ },
160
+ social: (provider, options) => client.loginSocial(provider, options)
161
+ };
162
+ }, [client]);
163
+ const signUp = useMemo(() => {
164
+ const h = client.headless;
165
+ return {
166
+ email: async (params) => {
167
+ const result = await h.signUp.email(params);
168
+ if (!result.requiresVerification) {
169
+ setSession({
170
+ accessToken: result.accessToken,
171
+ refreshToken: result.refreshToken,
172
+ expiresAt: result.expiresAt,
173
+ user: result.user
174
+ });
175
+ }
176
+ return result;
177
+ }
178
+ };
179
+ }, [client]);
114
180
  const value = useMemo(
115
181
  () => ({
116
182
  client,
@@ -121,9 +187,11 @@ function SmartHiveProvider({ children, ...config }) {
121
187
  logout,
122
188
  refreshSession,
123
189
  getAuthorizationHeader,
124
- authFetch
190
+ authFetch,
191
+ signIn,
192
+ signUp
125
193
  }),
126
- [client, session, isLoaded, login, logout, refreshSession, getAuthorizationHeader, authFetch]
194
+ [client, session, isLoaded, login, logout, refreshSession, getAuthorizationHeader, authFetch, signIn, signUp]
127
195
  );
128
196
  return /* @__PURE__ */ jsx(AuthContext.Provider, { value, children });
129
197
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/provider.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { Linking } from \"react-native\";\nimport { AuthRequest } from \"expo-auth-session\";\nimport * as SecureStore from \"expo-secure-store\";\nimport {\n initAuth,\n type AuthSession,\n type AuthStorage,\n type SmartHiveAuthClient,\n type SmartHiveAuthConfig,\n} from \"@smarthivelabs-devs/auth-sdk\";\n\n// ── Secure storage adapter ────────────────────────────────────────────────────\n\nconst secureStorage: AuthStorage = {\n getItem: (key) => SecureStore.getItemAsync(key),\n setItem: (key, value) => SecureStore.setItemAsync(key, value),\n removeItem: (key) => SecureStore.deleteItemAsync(key),\n};\n\nconst storageKeys = {\n pkceVerifier: \"smarthive.auth.pkce_verifier\",\n pkceState: \"smarthive.auth.pkce_state\"\n} as const;\n\n// ── Config ────────────────────────────────────────────────────────────────────\n\nexport interface SmartHiveExpoConfig extends Omit<SmartHiveAuthConfig, \"storage\"> {\n /** Deep link redirect URI, e.g. \"myapp://auth/callback\" */\n redirectUri: string;\n}\n\n/**\n * Build a deep link redirect URI from your Expo app scheme.\n * @example buildRedirectUri(\"myapp\") → \"myapp://auth/callback\"\n */\nexport function buildRedirectUri(scheme: string, path = \"auth/callback\"): string {\n return `${scheme}://${path}`;\n}\n\nfunction normalizeBaseUrl(baseUrl: string) {\n return baseUrl.replace(/\\/$/, \"\");\n}\n\n// ── Auth client (Expo flavour) ─────────────────────────────────────────────────\n\n/**\n * Creates an auth client that uses SecureStore for token storage and\n * Linking.openURL for the OAuth redirect (instead of location.assign).\n */\nexport function initExpoAuth(config: SmartHiveExpoConfig): SmartHiveAuthClient {\n const base = initAuth({\n ...config,\n storage: secureStorage,\n temporaryStorage: secureStorage\n } as SmartHiveAuthConfig);\n\n return {\n ...base,\n async login(options) {\n const redirectUri = options?.redirectUri ?? config.redirectUri;\n const authBase = normalizeBaseUrl(config.authDomain ?? config.baseUrl);\n const request = new AuthRequest({\n clientId: config.publishableKey,\n redirectUri,\n responseType: \"code\",\n usePKCE: true,\n state: options?.state,\n extraParams: {\n project_id: config.projectId,\n publishable_key: config.publishableKey\n }\n });\n const url = await request.makeAuthUrlAsync({\n authorizationEndpoint: `${authBase}/api/auth/oauth2/authorize`\n });\n\n if (request.codeVerifier) {\n await secureStorage.setItem(storageKeys.pkceVerifier, request.codeVerifier);\n }\n await secureStorage.setItem(storageKeys.pkceState, request.state);\n await Linking.openURL(url);\n },\n };\n}\n\n// ── Context ────────────────────────────────────────────────────────────────────\n\ninterface AuthContextValue {\n client: SmartHiveAuthClient;\n session: AuthSession | null;\n isLoaded: boolean;\n isSignedIn: boolean;\n login(options?: { redirectUri?: string }): Promise<void>;\n logout(): Promise<void>;\n refreshSession(): Promise<void>;\n getAuthorizationHeader(): Promise<Record<string, string>>;\n authFetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;\n}\n\nconst AuthContext = createContext<AuthContextValue | null>(null);\n\n// ── Provider ───────────────────────────────────────────────────────────────────\n\nexport interface SmartHiveProviderProps extends SmartHiveExpoConfig {\n children: React.ReactNode;\n}\n\n/**\n * Wraps your Expo app and provides auth state to all child components.\n * Tokens are stored in SecureStore. OAuth is handled via deep links.\n *\n * @example\n * <SmartHiveProvider\n * projectId=\"proj_...\"\n * publishableKey=\"pk_...\"\n * baseUrl=\"https://authcore.smarthivelabs.dev/prod\"\n * redirectUri=\"myapp://auth/callback\"\n * >\n * <App />\n * </SmartHiveProvider>\n */\nexport function SmartHiveProvider({ children, ...config }: SmartHiveProviderProps) {\n const configRef = useRef(config);\n const client = useMemo(() => initExpoAuth(configRef.current), []);\n\n const [session, setSession] = useState<AuthSession | null>(null);\n const [isLoaded, setIsLoaded] = useState(false);\n\n // Initial session load from SecureStore\n useEffect(() => {\n let cancelled = false;\n client\n .initialize()\n .then(() => client.getSession())\n .then((s) => { if (!cancelled) setSession(s); })\n .catch(() => {})\n .finally(() => { if (!cancelled) setIsLoaded(true); });\n return () => { cancelled = true; };\n }, [client]);\n\n // Deep link listener — catches the OAuth callback redirect back into the app\n useEffect(() => {\n function handleUrl({ url }: { url: string }) {\n client\n .handleCallback({ url })\n .then((s) => setSession(s))\n .catch(() => {});\n }\n\n const sub = Linking.addEventListener(\"url\", handleUrl);\n\n // Handle cold-start: app opened directly from the OAuth redirect URL\n Linking.getInitialURL().then((url) => {\n if (url) handleUrl({ url });\n });\n\n return () => sub.remove();\n }, [client]);\n\n const login = useCallback(\n (options?: { redirectUri?: string }) => client.login(options),\n [client]\n );\n\n const logout = useCallback(async () => {\n await client.logout();\n setSession(null);\n }, [client]);\n\n const refreshSession = useCallback(async () => {\n setSession(await client.refreshSession());\n }, [client]);\n\n const getAuthorizationHeader = useCallback(\n () => client.getAuthorizationHeader(),\n [client]\n );\n\n const authFetch = useCallback(\n (input: string | URL | Request, init?: RequestInit) => client.fetch(input, init),\n [client]\n );\n\n const value = useMemo<AuthContextValue>(\n () => ({\n client,\n session,\n isLoaded,\n isSignedIn: !!session,\n login,\n logout,\n refreshSession,\n getAuthorizationHeader,\n authFetch\n }),\n [client, session, isLoaded, login, logout, refreshSession, getAuthorizationHeader, authFetch]\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\n// ── Hooks ──────────────────────────────────────────────────────────────────────\n\nfunction useAuthContext(): AuthContextValue {\n const ctx = useContext(AuthContext);\n if (!ctx) throw new Error(\"useAuth must be used inside <SmartHiveProvider>.\");\n return ctx;\n}\n\nexport function useAuth() { return useAuthContext(); }\nexport function useSession() { return useAuthContext().session; }\nexport function useUser() { return useAuthContext().session?.user ?? null; }\nexport function useIsLoaded() { return useAuthContext().isLoaded; }\n\nexport function useIsSignedIn() {\n const { isLoaded, isSignedIn } = useAuthContext();\n return isLoaded ? isSignedIn : null;\n}\n\nexport function useAuthFetch() {\n return useAuthContext().authFetch;\n}\n\nexport function useAuthorizationHeader() {\n return useAuthContext().getAuthorizationHeader;\n}\n\n// ── Render helpers ─────────────────────────────────────────────────────────────\n\nexport function SignedIn({ children }: { children: React.ReactNode }) {\n const { isLoaded, isSignedIn } = useAuthContext();\n if (!isLoaded || !isSignedIn) return null;\n return <>{children}</>;\n}\n\nexport function SignedOut({ children }: { children: React.ReactNode }) {\n const { isLoaded, isSignedIn } = useAuthContext();\n if (!isLoaded || isSignedIn) return null;\n return <>{children}</>;\n}\n\nexport function AuthLoading({ children }: { children: React.ReactNode }) {\n const { isLoaded } = useAuthContext();\n return isLoaded ? null : <>{children}</>;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/provider.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { Linking } from \"react-native\";\nimport { AuthRequest } from \"expo-auth-session\";\nimport * as SecureStore from \"expo-secure-store\";\nimport {\n initAuth,\n envFromPublishableKey,\n type AuthSession,\n type AuthStorage,\n type HeadlessClient,\n type HeadlessSignInResult,\n type HeadlessSignUpResult,\n type SmartHiveAuthClient,\n type SmartHiveAuthConfig,\n type SocialProvider,\n} from \"@smarthivelabs-devs/auth-sdk\";\n\n// ── Secure storage adapter ────────────────────────────────────────────────────\n\nconst secureStorage: AuthStorage = {\n getItem: (key) => SecureStore.getItemAsync(key),\n setItem: (key, value) => SecureStore.setItemAsync(key, value),\n removeItem: (key) => SecureStore.deleteItemAsync(key),\n};\n\nconst storageKeys = {\n pkceVerifier: \"smarthive.auth.pkce_verifier\",\n pkceState: \"smarthive.auth.pkce_state\"\n} as const;\n\n// ── Config ────────────────────────────────────────────────────────────────────\n\nexport interface SmartHiveExpoConfig extends Omit<SmartHiveAuthConfig, \"storage\"> {\n /** Deep link redirect URI, e.g. \"myapp://auth/callback\" */\n redirectUri: string;\n}\n\n/**\n * Build a deep link redirect URI from your Expo app scheme.\n * @example buildRedirectUri(\"myapp\") → \"myapp://auth/callback\"\n */\nexport function buildRedirectUri(scheme: string, path = \"auth/callback\"): string {\n return `${scheme}://${path}`;\n}\n\nfunction normalizeBaseUrl(baseUrl: string) {\n return baseUrl.replace(/\\/$/, \"\");\n}\n\n// ── Auth client (Expo flavour) ─────────────────────────────────────────────────\n\n/**\n * Creates an auth client that uses SecureStore for token storage and\n * Linking.openURL for the OAuth redirect (instead of location.assign).\n */\nexport function initExpoAuth(config: SmartHiveExpoConfig): SmartHiveAuthClient {\n const base = initAuth({\n ...config,\n storage: secureStorage,\n temporaryStorage: secureStorage\n } as SmartHiveAuthConfig);\n\n return {\n ...base,\n async login(options) {\n const redirectUri = options?.redirectUri ?? config.redirectUri;\n const authBase = normalizeBaseUrl(config.authDomain ?? config.baseUrl);\n const request = new AuthRequest({\n clientId: config.publishableKey,\n redirectUri,\n responseType: \"code\",\n usePKCE: true,\n state: options?.state,\n extraParams: {\n project_id: config.projectId,\n publishable_key: config.publishableKey\n }\n });\n const url = await request.makeAuthUrlAsync({\n authorizationEndpoint: `${authBase}/api/auth/oauth2/authorize`\n });\n\n if (request.codeVerifier) {\n await secureStorage.setItem(storageKeys.pkceVerifier, request.codeVerifier);\n }\n await secureStorage.setItem(storageKeys.pkceState, request.state);\n await Linking.openURL(url);\n },\n\n async loginSocial(provider, options) {\n const redirectUri = options?.redirectUri ?? config.redirectUri;\n const authBase = normalizeBaseUrl(config.authDomain ?? config.baseUrl);\n const env = envFromPublishableKey(config.publishableKey);\n const url = new URL(`${authBase}/${env}/api/auth/social/${provider}`);\n url.searchParams.set(\"project_id\", config.projectId);\n url.searchParams.set(\"redirect_uri\", redirectUri);\n await Linking.openURL(url.toString());\n },\n };\n}\n\n// ── Context ────────────────────────────────────────────────────────────────────\n\ninterface AuthContextValue {\n client: SmartHiveAuthClient;\n session: AuthSession | null;\n isLoaded: boolean;\n isSignedIn: boolean;\n /** OAuth 2.0 + PKCE browser redirect sign-in (unchanged). */\n login(options?: { redirectUri?: string }): Promise<void>;\n logout(): Promise<void>;\n refreshSession(): Promise<void>;\n getAuthorizationHeader(): Promise<Record<string, string>>;\n authFetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;\n /**\n * Headless (no browser) sign-in methods for custom login screens.\n * Tokens are stored in SecureStore automatically on success.\n */\n signIn: {\n email(params: { email: string; password: string }): Promise<HeadlessSignInResult>;\n phone: {\n sendOtp(params: { phoneNumber: string }): Promise<void>;\n verify(params: { phoneNumber: string; code: string }): Promise<HeadlessSignInResult>;\n };\n emailOtp: {\n send(params: { email: string }): Promise<void>;\n verify(params: { email: string; code: string }): Promise<HeadlessSignInResult>;\n };\n magicLink: {\n send(params: { email: string; callbackURL?: string }): Promise<void>;\n };\n /** Initiate a social OAuth flow — opens the provider's consent screen via Linking. */\n social(provider: SocialProvider, options?: { redirectUri?: string }): Promise<void>;\n };\n signUp: {\n email(params: { email: string; password: string; name?: string }): Promise<HeadlessSignUpResult>;\n };\n}\n\nconst AuthContext = createContext<AuthContextValue | null>(null);\n\n// ── Provider ───────────────────────────────────────────────────────────────────\n\nexport interface SmartHiveProviderProps extends SmartHiveExpoConfig {\n children: React.ReactNode;\n}\n\n/**\n * Wraps your Expo app and provides auth state to all child components.\n * Tokens are stored in SecureStore. Supports both:\n * - OAuth 2.0 + PKCE browser redirect via `login()`\n * - Headless direct sign-in via `signIn.*` (no browser, custom login screens)\n */\nexport function SmartHiveProvider({ children, ...config }: SmartHiveProviderProps) {\n const configRef = useRef(config);\n const client = useMemo(() => initExpoAuth(configRef.current), []);\n\n const [session, setSession] = useState<AuthSession | null>(null);\n const [isLoaded, setIsLoaded] = useState(false);\n\n // Initial session load from SecureStore\n useEffect(() => {\n let cancelled = false;\n client\n .initialize()\n .then(() => client.getSession())\n .then((s) => { if (!cancelled) setSession(s); })\n .catch(() => {})\n .finally(() => { if (!cancelled) setIsLoaded(true); });\n return () => { cancelled = true; };\n }, [client]);\n\n // Deep link listener — catches both PKCE and social OAuth callbacks\n useEffect(() => {\n function handleUrl({ url }: { url: string }) {\n try {\n const parsed = new URL(url);\n if (parsed.searchParams.has(\"access_token\") || parsed.searchParams.has(\"error\")) {\n // Social auth callback — tokens already in URL params\n client\n .handleSocialCallback({ url })\n .then((s) => setSession(s))\n .catch(() => {});\n } else {\n // PKCE OAuth callback — exchange code for tokens\n client\n .handleCallback({ url })\n .then((s) => setSession(s))\n .catch(() => {});\n }\n } catch {\n // Unparseable URL — ignore\n }\n }\n\n const sub = Linking.addEventListener(\"url\", handleUrl);\n\n // Handle cold-start: app opened directly from the OAuth redirect URL\n Linking.getInitialURL().then((url) => {\n if (url) handleUrl({ url });\n });\n\n return () => sub.remove();\n }, [client]);\n\n const login = useCallback(\n (options?: { redirectUri?: string }) => client.login(options),\n [client]\n );\n\n const logout = useCallback(async () => {\n await client.logout();\n setSession(null);\n }, [client]);\n\n const refreshSession = useCallback(async () => {\n setSession(await client.refreshSession());\n }, [client]);\n\n const getAuthorizationHeader = useCallback(\n () => client.getAuthorizationHeader(),\n [client]\n );\n\n const authFetch = useCallback(\n (input: string | URL | Request, init?: RequestInit) => client.fetch(input, init),\n [client]\n );\n\n // ── Headless sign-in wrappers — save session + update state ──────────────────\n\n function wrapHeadlessSignIn(\n fn: (p: never) => Promise<HeadlessSignInResult>\n ) {\n return async (params: never) => {\n const result = await fn(params);\n setSession({\n accessToken: result.accessToken,\n refreshToken: result.refreshToken,\n expiresAt: result.expiresAt,\n user: result.user,\n });\n return result;\n };\n }\n\n const signIn = useMemo<AuthContextValue[\"signIn\"]>(() => {\n const h: HeadlessClient = client.headless;\n return {\n email: wrapHeadlessSignIn(h.signIn.email.bind(h.signIn) as never),\n phone: {\n sendOtp: (p) => h.signIn.phone.sendOtp(p),\n verify: wrapHeadlessSignIn(h.signIn.phone.verify.bind(h.signIn.phone) as never),\n },\n emailOtp: {\n send: (p) => h.signIn.emailOtp.send(p),\n verify: wrapHeadlessSignIn(h.signIn.emailOtp.verify.bind(h.signIn.emailOtp) as never),\n },\n magicLink: {\n send: (p) => h.signIn.magicLink.send(p),\n },\n social: (provider, options) => client.loginSocial(provider, options),\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client]);\n\n const signUp = useMemo<AuthContextValue[\"signUp\"]>(() => {\n const h: HeadlessClient = client.headless;\n return {\n email: async (params) => {\n const result = await h.signUp.email(params);\n if (!result.requiresVerification) {\n setSession({\n accessToken: result.accessToken,\n refreshToken: result.refreshToken,\n expiresAt: result.expiresAt,\n user: result.user,\n });\n }\n return result;\n },\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client]);\n\n const value = useMemo<AuthContextValue>(\n () => ({\n client,\n session,\n isLoaded,\n isSignedIn: !!session,\n login,\n logout,\n refreshSession,\n getAuthorizationHeader,\n authFetch,\n signIn,\n signUp,\n }),\n [client, session, isLoaded, login, logout, refreshSession, getAuthorizationHeader, authFetch, signIn, signUp]\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\n// ── Hooks ──────────────────────────────────────────────────────────────────────\n\nfunction useAuthContext(): AuthContextValue {\n const ctx = useContext(AuthContext);\n if (!ctx) throw new Error(\"useAuth must be used inside <SmartHiveProvider>.\");\n return ctx;\n}\n\nexport function useAuth() { return useAuthContext(); }\nexport function useSession() { return useAuthContext().session; }\nexport function useUser() { return useAuthContext().session?.user ?? null; }\nexport function useIsLoaded() { return useAuthContext().isLoaded; }\n\nexport function useIsSignedIn() {\n const { isLoaded, isSignedIn } = useAuthContext();\n return isLoaded ? isSignedIn : null;\n}\n\nexport function useAuthFetch() {\n return useAuthContext().authFetch;\n}\n\nexport function useAuthorizationHeader() {\n return useAuthContext().getAuthorizationHeader;\n}\n\n// ── Render helpers ─────────────────────────────────────────────────────────────\n\nexport function SignedIn({ children }: { children: React.ReactNode }) {\n const { isLoaded, isSignedIn } = useAuthContext();\n if (!isLoaded || !isSignedIn) return null;\n return <>{children}</>;\n}\n\nexport function SignedOut({ children }: { children: React.ReactNode }) {\n const { isLoaded, isSignedIn } = useAuthContext();\n if (!isLoaded || isSignedIn) return null;\n return <>{children}</>;\n}\n\nexport function AuthLoading({ children }: { children: React.ReactNode }) {\n const { isLoaded } = useAuthContext();\n return isLoaded ? null : <>{children}</>;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smarthivelabs-devs/auth-expo",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "SmartHive Auth provider, hooks, and SecureStore integration for React Native / Expo",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -25,7 +25,7 @@
25
25
  "LICENSE"
26
26
  ],
27
27
  "peerDependencies": {
28
- "@smarthivelabs-devs/auth-sdk": "^1.0.0",
28
+ "@smarthivelabs-devs/auth-sdk": "^1.2.0",
29
29
  "expo-auth-session": ">=5",
30
30
  "expo-secure-store": ">=12",
31
31
  "react": ">=18",
@@ -36,7 +36,7 @@
36
36
  "@types/react-native": "^0.73.0",
37
37
  "tsup": "^8.3.0",
38
38
  "typescript": "^5.7.3",
39
- "@smarthivelabs-devs/auth-sdk": "^1.0.0"
39
+ "@smarthivelabs-devs/auth-sdk": "^1.2.0"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "tsup",