react-native-nitro-auth 0.6.0 → 0.6.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.2 - 2026-06-07
4
+
5
+ ### Fixed
6
+
7
+ - Hardened Microsoft authority URL construction to reject absolute tenant URLs and invalid B2C domains while building valid B2C tenant/policy authority paths.
8
+
9
+ ### Changed
10
+
11
+ - Updated the Expo example SDK 56 patch dependencies so Expo Doctor passes cleanly.
12
+
13
+ ## 0.6.1 - 2026-05-21
14
+
15
+ ### Changed
16
+
17
+ - Updated the package and Expo example baseline to Expo SDK 56, React Native 0.85.3, React 19.2.3, TypeScript 6.0.3, Nitro Modules 0.35.7, and nitrogen 0.35.7.
18
+ - Raised the iOS deployment target to 16.4 for SDK 56 compatibility.
19
+ - Added release preflight checks for Expo dependency validation, Expo Doctor, config introspection, package build, tests, C++ tests, and publish dry run.
20
+ - Simplified the example app by keeping provider-specific advanced options collapsed by default.
21
+ - Updated README badges, setup commands, release checks, and typed API examples to match the 0.6.1 package state.
22
+ - Added compile-time coverage for provider-specific login option types.
23
+ - Added CI setup and versioned tool detection for LLVM C++ coverage tools.
24
+ - Added a CI-safe release preflight mode that skips unauthenticated npm publish dry runs while keeping local publish dry runs intact.
25
+
26
+ ### Fixed
27
+
28
+ - Retained the active iOS Apple Sign-In controller until completion to avoid premature native lifecycle cleanup.
29
+ - Removed the example app's import-time native logging side effect.
30
+ - Removed Turbo cache-output warnings from lint and typecheck tasks.
31
+
3
32
  ## 0.6.0 - 2026-05-14
4
33
 
5
34
  ### Added
package/README.md CHANGED
@@ -1,33 +1,18 @@
1
1
  # react-native-nitro-auth
2
2
 
3
- ![npm](https://img.shields.io/badge/npm-v0.6.0-f97316?style=flat-square)
4
- ![license](https://img.shields.io/badge/license-MIT-007ec6?style=flat-square)
5
- ![react-native](https://img.shields.io/badge/react--native-%3E%3D0.75-61dafb?style=flat-square)
6
- ![nitro-modules](https://img.shields.io/badge/nitro--modules-%3E%3D0.35.0-black?style=flat-square)
3
+ [![npm version](https://img.shields.io/npm/v/react-native-nitro-auth?color=f97316&label=npm)](https://www.npmjs.com/package/react-native-nitro-auth)
4
+ [![license](https://img.shields.io/npm/l/react-native-nitro-auth?color=007ec6)](https://github.com/JoaoPauloCMarra/react-native-nitro-auth/blob/main/LICENSE)
5
+ [![React Native](https://img.shields.io/badge/react--native-%3E%3D0.75-61dafb)](https://reactnative.dev/)
6
+ [![Expo](https://img.shields.io/badge/expo-SDK%2056-000020)](https://expo.dev/)
7
+ [![Nitro Modules](https://img.shields.io/badge/nitro--modules-%3E%3D0.35.7-black)](https://nitro.margelo.com/)
7
8
 
8
- Fast React Native authentication for Google Sign-In, Apple Sign-In, and Microsoft Entra ID, built on Nitro Modules and JSI.
9
+ Google Sign-In, Apple Sign-In, and Microsoft Entra ID for React Native and
10
+ Expo, powered by Nitro Modules.
9
11
 
10
- `react-native-nitro-auth` gives Expo and React Native apps one typed API for native social login, web OAuth, token refresh, incremental scopes, and auth state listeners without owning your app's long-term token storage.
11
-
12
- ## Why Use It?
13
-
14
- - One package for Google, Apple, and Microsoft authentication on React Native.
15
- - Native iOS and Android bridges powered by `react-native-nitro-modules`.
16
- - Expo config plugin for client IDs, URL schemes, entitlements, and Android resources.
17
- - Web implementation for Expo web with Google, Apple, and Microsoft OAuth.
18
- - Typed `useAuth()` hook, `AuthService`, `SocialButton`, and `AuthError`.
19
- - App-owned persistence model: tokens stay in memory unless your app stores a snapshot.
20
- - Built-in flows for silent restore, token refresh, account picker, login hints, and incremental Google scopes.
21
- - Consistent `AuthError` mapping for async `AuthService` failures on native and web.
22
-
23
- ## Choose Your Path
24
-
25
- | Need | Use |
26
- | ---------------------------------------------------------------------- | ----------------------------------------------------------------- |
27
- | Google, Apple, or Microsoft sign-in in an Expo or React Native app | `react-native-nitro-auth` |
28
- | Generic OAuth or OIDC provider not covered by this package | `expo-auth-session` or `react-native-app-auth` |
29
- | Firebase user management, password auth, MFA, and hosted auth platform | `@react-native-firebase/auth`, Auth0, Authgear, or your IDaaS SDK |
30
- | Server-side session validation | Your backend; client JWT decode is display-only |
12
+ Use it when you want one typed authentication API for native social login, web
13
+ OAuth, token refresh, incremental scopes, account listeners, and consistent
14
+ `AuthError` handling. The package keeps tokens in memory; your app decides what
15
+ to persist and where.
31
16
 
32
17
  ## Install
33
18
 
@@ -35,31 +20,25 @@ Fast React Native authentication for Google Sign-In, Apple Sign-In, and Microsof
35
20
  bun add react-native-nitro-auth react-native-nitro-modules
36
21
  ```
37
22
 
38
- For Expo projects, prebuild after adding the config plugin:
23
+ For Expo development builds:
39
24
 
40
25
  ```sh
41
- bunx expo prebuild --clean
26
+ bunx expo install react-native-nitro-auth react-native-nitro-modules
27
+ bunx expo prebuild
42
28
  ```
43
29
 
44
- For bare React Native projects, install pods after installing the package:
30
+ For bare React Native apps:
45
31
 
46
32
  ```sh
47
33
  cd ios && pod install
48
34
  ```
49
35
 
50
- ## Requirements
36
+ Expo Go cannot load Nitro native modules. Use an Expo development build or a
37
+ bare app.
51
38
 
52
- | Runtime | Requirement |
53
- | --------------------- | ---------------------------------------- |
54
- | React Native | `>=0.75` |
55
- | Nitro Modules | `>=0.35` |
56
- | iOS | 15.1+ recommended |
57
- | Android | min SDK 24+ recommended |
58
- | Expo example baseline | Expo SDK 55, React Native 0.83, React 19 |
39
+ ## Expo Config
59
40
 
60
- ## Expo Setup
61
-
62
- Add the plugin to `app.json` or `app.config.js`.
41
+ Add the plugin to `app.json` or `app.config.js` before prebuild:
63
42
 
64
43
  ```js
65
44
  export default {
@@ -99,443 +78,140 @@ export default {
99
78
  microsoftClientId: process.env.MICROSOFT_CLIENT_ID,
100
79
  microsoftTenant: process.env.MICROSOFT_TENANT,
101
80
  microsoftB2cDomain: process.env.MICROSOFT_B2C_DOMAIN,
102
- nitroAuthWebStorage: "memory",
103
- nitroAuthPersistTokensOnWeb: false,
81
+ nitroAuthWebStorage: "session",
104
82
  },
105
83
  },
106
84
  };
107
85
  ```
108
86
 
109
- ### Plugin Options
110
-
111
- | Option | Platform | Purpose |
112
- | ---------------------------- | -------- | ---------------------------------------------------------------------- |
113
- | `ios.googleClientId` | iOS | Google iOS OAuth client ID |
114
- | `ios.googleServerClientId` | iOS | Google web/server client ID for server auth code flows |
115
- | `ios.googleUrlScheme` | iOS | Reversed iOS client ID URL scheme |
116
- | `ios.appleSignIn` | iOS | Adds Apple Sign-In entitlement when `true` |
117
- | `ios.microsoftClientId` | iOS | Microsoft app/client ID |
118
- | `ios.microsoftTenant` | iOS | Microsoft tenant, `common`, `organizations`, `consumers`, or tenant ID |
119
- | `ios.microsoftB2cDomain` | iOS | Azure AD B2C domain |
120
- | `android.googleClientId` | Android | Google web OAuth client ID |
121
- | `android.microsoftClientId` | Android | Microsoft app/client ID |
122
- | `android.microsoftTenant` | Android | Microsoft tenant |
123
- | `android.microsoftB2cDomain` | Android | Azure AD B2C domain |
124
-
125
- ## Provider Setup
126
-
127
- ### Google Sign-In
128
-
129
- Create OAuth clients in Google Cloud Console:
130
-
131
- - iOS client ID for your bundle identifier.
132
- - Web client ID for Android, web, and server auth code flows.
133
- - Android SHA-1/SHA-256 entries for local debug and release signing.
134
-
135
- Use the iOS reversed client ID as `GOOGLE_IOS_URL_SCHEME`.
136
-
137
- ### Apple Sign-In
138
-
139
- Set `ios.appleSignIn: true` in the config plugin. Apple returns name and email only on the first authorization for a user. Store any profile fields you need in your own backend or app state.
140
-
141
- Apple Sign-In is supported on iOS and web. It is intentionally reported as `unsupported_provider` on Android.
142
-
143
- ### Microsoft Entra ID
144
-
145
- Create an app registration in Microsoft Entra ID and add redirect URIs:
146
-
147
- - iOS: `msauth.<bundleIdentifier>://auth`
148
- - Android: `msauth://<androidPackage>/<clientId>`
149
- - Web: your web origin, for example `https://app.example.com`
150
-
151
- Use `microsoftTenant` for `common`, `organizations`, `consumers`, a tenant ID, or a B2C policy path. Use `microsoftB2cDomain` for Azure AD B2C.
87
+ Plugin options:
88
+
89
+ | Option | Platform | Required for |
90
+ | ---------------------------- | -------- | -------------------------------- |
91
+ | `ios.googleClientId` | iOS | Google Sign-In on iOS. |
92
+ | `ios.googleServerClientId` | iOS | Google server auth code flow. |
93
+ | `ios.googleUrlScheme` | iOS | Google redirect URL scheme. |
94
+ | `ios.appleSignIn` | iOS | Apple Sign-In entitlement. |
95
+ | `ios.microsoftClientId` | iOS | Microsoft Entra ID native login. |
96
+ | `ios.microsoftTenant` | iOS | Microsoft tenant override. |
97
+ | `ios.microsoftB2cDomain` | iOS | Microsoft B2C hostname. |
98
+ | `android.googleClientId` | Android | Google Sign-In on Android. |
99
+ | `android.microsoftClientId` | Android | Microsoft Entra ID native login. |
100
+ | `android.microsoftTenant` | Android | Microsoft tenant override. |
101
+ | `android.microsoftB2cDomain` | Android | Microsoft B2C hostname. |
102
+
103
+ Web reads provider client IDs from `expo.extra`; native platforms read values
104
+ written by the plugin during prebuild.
105
+
106
+ Microsoft tenant values are validated before opening the authorization URL. Use
107
+ `common`, `organizations`, `consumers`, a tenant ID, or a tenant domain for
108
+ standard Entra ID. For B2C, set `microsoftB2cDomain` to a hostname such as
109
+ `contoso.b2clogin.com` and set `microsoftTenant` to a policy such as
110
+ `B2C_1_signin`. For custom B2C domains, set `microsoftTenant` to a tenant/policy
111
+ path such as `contoso.onmicrosoft.com/B2C_1_signin`.
152
112
 
153
113
  ## Quick Start
154
114
 
155
115
  ```tsx
156
- import { Button, Text, View } from "react-native";
157
- import { AuthError, useAuth } from "react-native-nitro-auth";
116
+ import { AuthService, AuthProvider, useAuth } from "react-native-nitro-auth";
158
117
 
159
- export function SignInScreen() {
160
- const { user, loading, login, logout, getAccessToken } = useAuth();
118
+ export function SignInButton() {
119
+ const { user, login, logout, loading, error } = useAuth();
161
120
 
162
121
  async function signInWithGoogle() {
163
- try {
164
- await login("google", {
165
- scopes: ["email", "profile"],
166
- });
167
- } catch (e) {
168
- const error = AuthError.from(e);
169
- console.warn(error.code, error.underlyingMessage);
170
- }
122
+ await login(AuthProvider.Google, {
123
+ scopes: ["openid", "profile", "email"],
124
+ });
171
125
  }
172
126
 
173
- async function readToken() {
174
- const token = await getAccessToken();
175
- console.log(token);
127
+ if (user) {
128
+ return <Button title="Sign out" onPress={logout} />;
176
129
  }
177
130
 
178
- return (
179
- <View>
180
- <Text>{user?.email ?? "Signed out"}</Text>
181
- <Button
182
- title={loading ? "Signing in..." : "Sign in with Google"}
183
- onPress={signInWithGoogle}
184
- />
185
- <Button title="Get access token" onPress={readToken} />
186
- <Button title="Sign out" onPress={logout} />
187
- </View>
188
- );
189
- }
190
- ```
191
-
192
- ## SocialButton
193
-
194
- ```tsx
195
- import { SocialButton } from "react-native-nitro-auth";
196
-
197
- export function AuthButtons() {
198
- return (
199
- <>
200
- <SocialButton provider="google" />
201
- <SocialButton provider="apple" variant="black" />
202
- <SocialButton provider="microsoft" variant="outline" />
203
- </>
204
- );
131
+ return <Button title="Continue with Google" onPress={signInWithGoogle} />;
205
132
  }
206
- ```
207
-
208
- ## AuthService
209
133
 
210
- Use `AuthService` when you need auth outside React components.
211
-
212
- ```ts
213
- import { AuthService } from "react-native-nitro-auth";
214
-
215
- await AuthService.silentRestore();
216
-
217
- const unsubscribe = AuthService.onAuthStateChanged((user) => {
218
- console.log(user?.email);
219
- });
220
-
221
- const tokensUnsubscribe = AuthService.onTokensRefreshed((tokens) => {
222
- console.log(tokens.expirationTime);
223
- });
224
-
225
- unsubscribe();
226
- tokensUnsubscribe();
227
- ```
228
-
229
- ## Login Options
230
-
231
- ```ts
232
- await login("google", {
233
- scopes: ["email", "profile"],
234
- loginHint: "user@example.com",
235
- nonce: "opaque-nonce",
236
- useOneTap: true,
237
- forceAccountPicker: true,
238
- filterByAuthorizedAccounts: true,
239
- useLegacyGoogleSignIn: true,
240
- forceCodeForRefreshToken: true,
241
- hostedDomain: "company.com",
242
- requestVerifiedPhoneNumber: true,
243
- });
244
-
245
- await login("apple", {
246
- scopes: ["email", "name"],
247
- nonce: "opaque-nonce",
248
- });
249
-
250
- await login("microsoft", {
251
- scopes: ["openid", "profile", "email", "offline_access", "User.Read"],
252
- loginHint: "user@example.com",
134
+ await AuthService.login(AuthProvider.Microsoft, {
253
135
  tenant: "organizations",
254
- prompt: "select_account",
255
136
  });
256
137
  ```
257
138
 
258
- | Option | Provider | Platform | Notes |
259
- | ---------------------------- | ------------ | ---------------- | ----------------------------------------------------------- |
260
- | `scopes` | All | iOS, Android, web | Requested OAuth scopes. Apple is unavailable on Android. |
261
- | `loginHint` | Google, Microsoft | iOS, Android, web | Prefills account selection when supported by the provider. |
262
- | `nonce` | Google, Apple | iOS, Android, web | Passed to provider ID-token flows when the SDK supports it. |
263
- | `useOneTap` | Google | Android | Enables Credential Manager auto-select. |
264
- | `useSheet` | Google | iOS | Compatibility alias; prefer `forceAccountPicker`. |
265
- | `forceAccountPicker` | Google | iOS, Android, web | Forces an account picker. Android uses the legacy chooser. |
266
- | `filterByAuthorizedAccounts` | Google | Android | Limits Credential Manager to authorized accounts. |
267
- | `useLegacyGoogleSignIn` | Google | Android | Uses legacy Google Sign-In for server auth code flows. |
268
- | `forceCodeForRefreshToken` | Google | Android | Forces a new server auth code on the legacy Google path. |
269
- | `hostedDomain` | Google | iOS, Android, web | Hints or filters Google Workspace hosted-domain accounts. |
270
- | `openIDRealm` | Google | iOS, web | Adds OpenID realm support where the SDK exposes it. |
271
- | `requestVerifiedPhoneNumber` | Google | Android | Requests verified phone number through Credential Manager. |
272
- | `tenant` | Microsoft | iOS, Android, web | Overrides configured tenant. |
273
- | `prompt` | Microsoft | iOS, Android, web | `login`, `consent`, `select_account`, or `none`. |
274
-
275
- ## Incremental Scopes
276
-
277
- ```ts
278
- const calendarScope = "https://www.googleapis.com/auth/calendar.readonly";
279
-
280
- await requestScopes([calendarScope]);
281
- await revokeScopes([calendarScope]);
282
- ```
283
-
284
- On Android, incremental Google scope requests use the legacy Google Sign-In APIs because Credential Manager does not expose an equivalent existing-account scope query.
285
-
286
- ## Storage Model
287
-
288
- Native tokens are kept in memory by design. The package does not persist Microsoft refresh tokens or provider tokens to disk. Your app owns persistence and secure storage policy.
139
+ ## Providers
289
140
 
290
- For app-managed persistence, store only the minimum state your product needs:
141
+ | Provider | Native | Web | Notes |
142
+ | --------- | ------------ | --- | --------------------------------------------------------------------- |
143
+ | Google | iOS, Android | Yes | Supports account picker, login hint, refresh, and incremental scopes. |
144
+ | Apple | iOS | Yes | Apple returns name and email only on first authorization. |
145
+ | Microsoft | iOS, Android | Yes | Supports tenant and B2C configuration. |
291
146
 
292
- ```ts
293
- import { AuthService } from "react-native-nitro-auth";
147
+ Use `expo-auth-session`, `react-native-app-auth`, Auth0, Firebase Auth, or your
148
+ identity provider SDK when you need a generic OAuth/OIDC provider, password
149
+ auth, MFA, hosted user management, or server session management.
294
150
 
295
- const snapshot = {
296
- user: AuthService.currentUser,
297
- scopes: AuthService.grantedScopes,
298
- updatedAt: Date.now(),
299
- };
300
- ```
301
-
302
- On web, the default is also memory storage. You can opt into browser storage with:
303
-
304
- ```js
305
- extra: {
306
- nitroAuthWebStorage: "session", // "session", "local", or "memory"
307
- nitroAuthPersistTokensOnWeb: true,
308
- }
309
- ```
310
-
311
- ## Error Contract
312
-
313
- All public async APIs throw `AuthError`, including provider errors surfaced by native and web `AuthService` implementations.
314
-
315
- ```ts
316
- try {
317
- await AuthService.login("microsoft");
318
- } catch (e) {
319
- const error = AuthError.from(e);
320
- switch (error.code) {
321
- case "cancelled":
322
- break;
323
- case "configuration_error":
324
- break;
325
- case "token_error":
326
- break;
327
- default:
328
- break;
329
- }
330
- }
331
- ```
332
-
333
- Known error codes:
334
-
335
- ```ts
336
- type AuthErrorCode =
337
- | "cancelled"
338
- | "timeout"
339
- | "popup_blocked"
340
- | "network_error"
341
- | "configuration_error"
342
- | "not_signed_in"
343
- | "operation_in_progress"
344
- | "unsupported_provider"
345
- | "invalid_state"
346
- | "invalid_nonce"
347
- | "token_error"
348
- | "no_id_token"
349
- | "parse_error"
350
- | "refresh_failed"
351
- | "unknown";
352
- ```
353
-
354
- `underlyingMessage` keeps the raw native or OAuth message when it differs from the stable code.
355
-
356
- ## API Reference
357
-
358
- ### Exports
359
-
360
- ```ts
361
- export * from "react-native-nitro-auth";
362
- ```
151
+ ## API
363
152
 
364
153
  Main exports:
365
154
 
366
- - `useAuth()`
367
- - `AuthService`
368
- - `SocialButton`
369
- - `AuthError`
370
- - `isAuthErrorCode()`
371
- - `toAuthErrorCode()`
372
- - `AuthProvider`
373
- - `AuthUser`
374
- - `AuthTokens`
375
- - `LoginOptions`
376
- - `ProviderLoginOptions`
377
- - `LoginOptionsByProvider`
378
- - `GoogleLoginOptions`
379
- - `GoogleIOSLoginOptions`
380
- - `GoogleAndroidLoginOptions`
381
- - `GoogleWebLoginOptions`
382
- - `AppleLoginOptions`
383
- - `AppleIOSLoginOptions`
384
- - `AppleWebLoginOptions`
385
- - `MicrosoftLoginOptions`
386
- - `AuthLogin`
387
- - `TypedAuth`
388
-
389
- ### useAuth()
390
-
391
- ```ts
392
- type UseAuthReturn = {
393
- user: AuthUser | undefined;
394
- scopes: string[];
395
- loading: boolean;
396
- error: AuthError | undefined;
397
- hasPlayServices: boolean;
398
- login(provider: AuthProvider, options?: LoginOptions): Promise<void>;
399
- logout(): void;
400
- requestScopes(scopes: string[]): Promise<void>;
401
- revokeScopes(scopes: string[]): Promise<void>;
402
- revokeAccess(): Promise<void>;
403
- getAccessToken(): Promise<string | undefined>;
404
- refreshToken(): Promise<AuthTokens>;
405
- silentRestore(): Promise<void>;
406
- };
407
- ```
408
-
409
- ### Strong Login Types
410
-
411
- `AuthService.login()` and `useAuth().login()` infer the allowed option object from the provider argument.
412
-
413
- ```ts
414
- await AuthService.login("apple", {
415
- nonce: "opaque-nonce",
416
- });
417
-
418
- await AuthService.login("microsoft", {
419
- tenant: "organizations",
420
- prompt: "select_account",
421
- });
422
- ```
423
-
424
- Provider/platform option helpers are exported for config builders and AI-generated integrations:
425
-
426
- ```ts
427
- import type {
428
- GoogleAndroidLoginOptions,
429
- GoogleIOSLoginOptions,
430
- MicrosoftLoginOptions,
431
- } from "react-native-nitro-auth";
155
+ - `useAuth()` for React state, login, logout, refresh, and listeners.
156
+ - `AuthService` for imperative login, refresh, logout, and user reads.
157
+ - `SocialButton` for provider-aware UI.
158
+ - `AuthProvider` for Google, Apple, and Microsoft provider names.
159
+ - `AuthError` and `AuthErrorCode` for deterministic failures.
160
+ - Provider option types for strongly typed login calls.
432
161
 
433
- const androidGoogleOptions = {
434
- useOneTap: true,
435
- filterByAuthorizedAccounts: true,
436
- requestVerifiedPhoneNumber: true,
437
- } satisfies GoogleAndroidLoginOptions;
162
+ Login options include `scopes`, `loginHint`, `accountId`, `forceRefresh`,
163
+ `nonce`, `state`, `tenant`, `prompt`, and provider-specific fields.
438
164
 
439
- const iosGoogleOptions = {
440
- hostedDomain: "company.com",
441
- openIDRealm: "https://example.com",
442
- } satisfies GoogleIOSLoginOptions;
165
+ ## Storage Model
443
166
 
444
- const microsoftOptions = {
445
- tenant: "organizations",
446
- prompt: "select_account",
447
- } satisfies MicrosoftLoginOptions;
448
- ```
167
+ Tokens are held in memory. Persist only the snapshot your app actually needs,
168
+ preferably in your own secure storage or backend session. JWT decode on the
169
+ client is for display and routing only; signature validation belongs on your
170
+ server.
449
171
 
450
- ### AuthUser
451
-
452
- ```ts
453
- type AuthUser = {
454
- provider: "google" | "apple" | "microsoft";
455
- email?: string;
456
- name?: string;
457
- photo?: string;
458
- idToken?: string;
459
- accessToken?: string;
460
- refreshToken?: string;
461
- serverAuthCode?: string;
462
- authorizationCode?: string;
463
- userId?: string;
464
- phoneNumber?: string;
465
- hostedDomain?: string;
466
- scopes?: string[];
467
- expirationTime?: number;
468
- underlyingError?: string;
469
- };
470
- ```
172
+ ## Error Contract
471
173
 
472
- ## Example App
174
+ Async public APIs throw `AuthError` with a stable `code`, `provider`, `platform`,
175
+ and `message`. Use `instanceof AuthError` when branching in UI code.
473
176
 
474
- The example app is the fastest way to verify setup and read a complete integration.
177
+ Common codes include `cancelled`, `configuration_error`, `network_error`,
178
+ `provider_unavailable`, `token_refresh_failed`, and `unknown`.
475
179
 
476
- ```sh
477
- cp apps/example/.env.example apps/example/.env.local
478
- bun install
479
- bun example:prebuild:clean
480
- bun example:ios
481
- bun example:android
482
- ```
180
+ ## Platform Support
483
181
 
484
- The demo includes:
182
+ | Platform | Status |
183
+ | -------- | ----------------------------------------------------------- |
184
+ | iOS | Google, Apple, Microsoft native flows. |
185
+ | Android | Google and Microsoft native flows. |
186
+ | Web | Google, Apple, and Microsoft OAuth through Expo web config. |
187
+ | Expo | Development builds with the config plugin. |
485
188
 
486
- - Provider cards for Google, Apple, and Microsoft.
487
- - Token and scope operations.
488
- - Silent restore, account picker, revoke access, and native logging actions.
489
- - Platform-gated controls for each supported Google, Apple, and Microsoft option.
490
- - App-owned disk snapshot example with `react-native-nitro-storage`.
491
- - Runtime smoke tests for the public API.
189
+ Validated baseline: Expo SDK 56, React Native 0.85.3, React 19.2.3, and Nitro
190
+ Modules 0.35.7.
492
191
 
493
192
  ## Troubleshooting
494
193
 
495
- | Symptom | Check |
496
- | ------------------------------------- | -------------------------------------------------------------------------------- |
497
- | `configuration_error` on Google | Client ID is missing or wrong for the current platform |
498
- | Google works in debug but not release | Add release SHA-1/SHA-256 fingerprints to Google Cloud Console |
499
- | Android `hasPlayServices` is false | Use an emulator image with Google Play Services |
500
- | Apple email/name missing | Apple only returns these fields on first authorization |
501
- | Microsoft `invalid_state` | Redirect URI or app resume path is wrong, or an old auth redirect completed late |
502
- | Microsoft `token_error` | Check tenant, client ID, redirect URI, and requested scopes |
503
- | Web popup blocked | Call `login()` from a user gesture such as a button press |
504
- | `operation_in_progress` | A provider flow is already active; wait for it to finish or sign out |
505
-
506
- ## Production Notes
194
+ - **Expo Go error:** build a dev client; Expo Go cannot load Nitro modules.
195
+ - **Provider not configured:** verify plugin values, `expo.extra`, and that you
196
+ prebuilt after changing config.
197
+ - **Apple profile missing name/email:** Apple only sends those fields on the
198
+ first authorization.
199
+ - **Microsoft redirect mismatch:** confirm bundle ID, Android package,
200
+ `microsoftClientId`, and tenant/B2C settings match the provider console.
507
201
 
508
- - Verify ID tokens on your backend. Client-side JWT parsing is for display and expiration hints only.
509
- - Store refresh tokens only in storage your app explicitly owns and secures.
510
- - Keep Google debug and release signing fingerprints in sync with your OAuth clients.
511
- - Add provider-specific redirect URIs for every environment.
512
- - Run the example app on iOS and Android before shipping provider config changes.
513
-
514
- ## Release Checks
515
-
516
- ```sh
517
- bun run publish-package:dry-run
518
- ```
519
-
520
- The publish script runs frozen install, core-version verification, codegen, build, lint, typecheck, Jest, JS coverage, C++ tests, C++ coverage, Expo Doctor, package docs sync, pack dry run, and `bun publish --dry-run --ignore-scripts`.
521
-
522
- For faster local iteration before the full release dry run:
202
+ ## Development
523
203
 
524
204
  ```sh
205
+ bun install
525
206
  bun run check
526
- bun run test:cpp
527
- bun run --cwd packages/react-native-nitro-auth test:coverage -- --runInBand
528
- bun run --cwd packages/react-native-nitro-auth test:cpp:coverage
529
- ```
530
-
531
- Before shipping provider or native config changes, also verify the example app:
532
-
533
- ```sh
534
- bun run example:prebuild
207
+ bun run release:preflight
535
208
  bun run example:android
536
209
  bun run example:ios
537
210
  ```
538
211
 
212
+ Run native example builds before release when changing plugin, native, Nitro, or
213
+ packaging files.
214
+
539
215
  ## License
540
216
 
541
217
  MIT