react-native-nitro-auth 0.5.1 → 0.5.4
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 +362 -190
- package/android/build.gradle +2 -5
- package/android/src/main/cpp/PlatformAuth+Android.cpp +84 -18
- package/android/src/main/java/com/auth/AuthAdapter.kt +82 -182
- package/android/src/main/java/com/auth/NitroAuthPackage.kt +1 -1
- package/app.plugin.js +2 -9
- package/cpp/AuthCache.cpp +0 -134
- package/cpp/AuthCache.hpp +0 -7
- package/cpp/HybridAuth.cpp +57 -63
- package/cpp/HybridAuth.hpp +3 -4
- package/ios/AuthAdapter.swift +23 -25
- package/lib/commonjs/Auth.web.js +523 -201
- package/lib/commonjs/Auth.web.js.map +1 -1
- package/lib/commonjs/index.js +0 -12
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +0 -12
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/js-storage-adapter.js +2 -0
- package/lib/commonjs/js-storage-adapter.js.map +1 -0
- package/lib/commonjs/service.js +9 -86
- package/lib/commonjs/service.js.map +1 -1
- package/lib/commonjs/service.web.js +1 -5
- package/lib/commonjs/service.web.js.map +1 -1
- package/lib/commonjs/ui/social-button.js +44 -29
- package/lib/commonjs/ui/social-button.js.map +1 -1
- package/lib/commonjs/ui/social-button.web.js +44 -29
- package/lib/commonjs/ui/social-button.web.js.map +1 -1
- package/lib/commonjs/use-auth.js +56 -42
- package/lib/commonjs/use-auth.js.map +1 -1
- package/lib/commonjs/utils/logger.js +12 -4
- package/lib/commonjs/utils/logger.js.map +1 -1
- package/lib/module/Auth.web.js +523 -201
- package/lib/module/Auth.web.js.map +1 -1
- package/lib/module/index.js +0 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +0 -1
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/js-storage-adapter.js +2 -0
- package/lib/module/js-storage-adapter.js.map +1 -0
- package/lib/module/service.js +9 -86
- package/lib/module/service.js.map +1 -1
- package/lib/module/service.web.js +1 -5
- package/lib/module/service.web.js.map +1 -1
- package/lib/module/ui/social-button.js +44 -29
- package/lib/module/ui/social-button.js.map +1 -1
- package/lib/module/ui/social-button.web.js +44 -29
- package/lib/module/ui/social-button.web.js.map +1 -1
- package/lib/module/use-auth.js +56 -42
- package/lib/module/use-auth.js.map +1 -1
- package/lib/module/utils/logger.js +12 -4
- package/lib/module/utils/logger.js.map +1 -1
- package/lib/typescript/commonjs/Auth.nitro.d.ts +3 -3
- package/lib/typescript/commonjs/Auth.nitro.d.ts.map +1 -1
- package/lib/typescript/commonjs/Auth.web.d.ts +25 -6
- package/lib/typescript/commonjs/Auth.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +1 -2
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +0 -1
- package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/js-storage-adapter.d.ts +6 -0
- package/lib/typescript/commonjs/js-storage-adapter.d.ts.map +1 -0
- package/lib/typescript/commonjs/service.d.ts +1 -8
- package/lib/typescript/commonjs/service.d.ts.map +1 -1
- package/lib/typescript/commonjs/service.web.d.ts +1 -8
- package/lib/typescript/commonjs/service.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/social-button.d.ts +6 -6
- package/lib/typescript/commonjs/ui/social-button.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/social-button.web.d.ts +6 -6
- package/lib/typescript/commonjs/ui/social-button.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/use-auth.d.ts +4 -4
- package/lib/typescript/commonjs/use-auth.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/logger.d.ts +4 -4
- package/lib/typescript/commonjs/utils/logger.d.ts.map +1 -1
- package/lib/typescript/module/Auth.nitro.d.ts +3 -3
- package/lib/typescript/module/Auth.nitro.d.ts.map +1 -1
- package/lib/typescript/module/Auth.web.d.ts +25 -6
- package/lib/typescript/module/Auth.web.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +1 -2
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/index.web.d.ts +0 -1
- package/lib/typescript/module/index.web.d.ts.map +1 -1
- package/lib/typescript/module/js-storage-adapter.d.ts +6 -0
- package/lib/typescript/module/js-storage-adapter.d.ts.map +1 -0
- package/lib/typescript/module/service.d.ts +1 -8
- package/lib/typescript/module/service.d.ts.map +1 -1
- package/lib/typescript/module/service.web.d.ts +1 -8
- package/lib/typescript/module/service.web.d.ts.map +1 -1
- package/lib/typescript/module/ui/social-button.d.ts +6 -6
- package/lib/typescript/module/ui/social-button.d.ts.map +1 -1
- package/lib/typescript/module/ui/social-button.web.d.ts +6 -6
- package/lib/typescript/module/ui/social-button.web.d.ts.map +1 -1
- package/lib/typescript/module/use-auth.d.ts +4 -4
- package/lib/typescript/module/use-auth.d.ts.map +1 -1
- package/lib/typescript/module/utils/logger.d.ts +4 -4
- package/lib/typescript/module/utils/logger.d.ts.map +1 -1
- package/nitrogen/generated/android/NitroAuth+autolinking.cmake +0 -1
- package/nitrogen/generated/shared/c++/AuthTokens.hpp +5 -1
- package/nitrogen/generated/shared/c++/AuthUser.hpp +5 -1
- package/nitrogen/generated/shared/c++/HybridAuthSpec.cpp +0 -1
- package/nitrogen/generated/shared/c++/HybridAuthSpec.hpp +0 -5
- package/package.json +11 -8
- package/react-native-nitro-auth.podspec +1 -1
- package/src/Auth.nitro.ts +4 -3
- package/src/Auth.web.ts +700 -246
- package/src/global.d.ts +0 -1
- package/src/index.ts +1 -2
- package/src/index.web.ts +0 -1
- package/src/js-storage-adapter.ts +5 -0
- package/src/service.ts +13 -106
- package/src/service.web.ts +0 -7
- package/src/ui/social-button.tsx +66 -43
- package/src/ui/social-button.web.tsx +67 -44
- package/src/use-auth.ts +116 -72
- package/src/utils/logger.ts +12 -4
- package/ios/KeychainStore.swift +0 -43
- package/lib/commonjs/AuthStorage.nitro.js +0 -6
- package/lib/commonjs/AuthStorage.nitro.js.map +0 -1
- package/lib/module/AuthStorage.nitro.js +0 -4
- package/lib/module/AuthStorage.nitro.js.map +0 -1
- package/lib/typescript/commonjs/AuthStorage.nitro.d.ts +0 -26
- package/lib/typescript/commonjs/AuthStorage.nitro.d.ts.map +0 -1
- package/lib/typescript/module/AuthStorage.nitro.d.ts +0 -26
- package/lib/typescript/module/AuthStorage.nitro.d.ts.map +0 -1
- package/nitrogen/generated/shared/c++/HybridAuthStorageAdapterSpec.cpp +0 -23
- package/nitrogen/generated/shared/c++/HybridAuthStorageAdapterSpec.hpp +0 -65
- package/src/AuthStorage.nitro.ts +0 -26
package/README.md
CHANGED
|
@@ -12,12 +12,13 @@ Nitro Auth is a modern authentication library for React Native built on top of [
|
|
|
12
12
|
|
|
13
13
|
Nitro Auth is designed to replace legacy modules like `@react-native-google-signin/google-signin` with a modern, high-performance architecture.
|
|
14
14
|
|
|
15
|
-
| Feature
|
|
16
|
-
|
|
|
17
|
-
| **Performance**
|
|
18
|
-
| **
|
|
19
|
-
| **Setup**
|
|
20
|
-
| **Types**
|
|
15
|
+
| Feature | Legacy Modules | Nitro Auth |
|
|
16
|
+
| :---------------- | :--------------------------- | :----------------------------------------------------------------------------- |
|
|
17
|
+
| **Performance** | Async bridge overhead (JSON) | **Direct JSI C++ (Zero-copy)** |
|
|
18
|
+
| **Storage** | Varies / Hidden defaults | **Native: in-memory only; Web: session cache (tokens memory-only by default)** |
|
|
19
|
+
| **Setup** | Manual async initialization | **Sync & declarative plugins** |
|
|
20
|
+
| **Types** | Manual / Brittle | **Fully Generated (Nitrogen)** |
|
|
21
|
+
| **Provider Data** | Varies | **Normalized auth payload** |
|
|
21
22
|
|
|
22
23
|
## Features
|
|
23
24
|
|
|
@@ -26,24 +27,56 @@ Nitro Auth is designed to replace legacy modules like `@react-native-google-sign
|
|
|
26
27
|
- **Incremental Auth**: Request additional OAuth scopes on the fly.
|
|
27
28
|
- **Expo Ready**: Comes with a powerful Config Plugin for zero-config setup.
|
|
28
29
|
- **Cross-Platform**: Unified API for iOS, Android, and Web.
|
|
29
|
-
- **
|
|
30
|
+
- **Token Lifecycle Helpers**: `getAccessToken()` refreshes near-expiry tokens; `refreshToken()` allows explicit refresh control.
|
|
30
31
|
- **Google One-Tap / Sheet**: Modern login experience on Android (Credential Manager) and iOS (Sign-In Sheet).
|
|
31
32
|
- **Error Metadata**: Detailed native error messages for easier debugging.
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
33
|
+
- **Normalized Provider Payload**: Exposes provider/user/token fields in a consistent cross-platform shape.
|
|
34
|
+
- **App-Owned Persistence**: Native is stateless by default. Web keeps a non-sensitive session snapshot; apps decide long-term persistence strategy.
|
|
35
|
+
|
|
36
|
+
## Design Philosophy
|
|
37
|
+
|
|
38
|
+
This is an **auth-only package** - on **native** (iOS/Android) it does NOT store auth data by default.
|
|
39
|
+
On **web**, Nitro Auth stores a non-sensitive auth snapshot in `sessionStorage` by default; sensitive tokens stay memory-only unless explicitly enabled.
|
|
40
|
+
|
|
41
|
+
The package provides:
|
|
42
|
+
|
|
43
|
+
- Login/logout functionality for Google, Apple, and Microsoft
|
|
44
|
+
- Token management (access token, refresh token, ID token)
|
|
45
|
+
- Scope management (request/revoke scopes)
|
|
46
|
+
- Consistent provider/user/token field exposure across iOS, Android, and Web
|
|
47
|
+
|
|
48
|
+
**Storage is the responsibility of the app using this package.** Use your own storage layer (for example [react-native-nitro-storage](https://github.com/JoaoPauloCMarra/react-native-nitro-storage)) to persist app-level auth snapshots/tokens when needed.
|
|
49
|
+
|
|
50
|
+
### Provider Data Availability
|
|
51
|
+
|
|
52
|
+
Token/data shape is normalized, but provider SDKs do not always return all fields at login time:
|
|
53
|
+
|
|
54
|
+
| Provider + Flow | `idToken` | `accessToken` | `serverAuthCode` | `expirationTime` |
|
|
55
|
+
| --------------------------- | ---------- | ---------------------------- | ---------------------------- | ----------------------------------- |
|
|
56
|
+
| Google (iOS) | Usually ✅ | Provider-dependent | Optional (if configured) | Optional |
|
|
57
|
+
| Google (Android One-Tap) | ✅ | Usually `undefined` at login | `undefined` | Derived from ID token when possible |
|
|
58
|
+
| Google (Android Legacy) | ✅ | Usually `undefined` at login | ✅ (if server client is set) | Derived from ID token when possible |
|
|
59
|
+
| Google (Web) | ✅ | ✅ | Optional (`code`) | Usually ✅ |
|
|
60
|
+
| Microsoft (iOS/Android/Web) | ✅ | Usually ✅ | `undefined` | Usually ✅ |
|
|
61
|
+
| Apple (iOS/Web) | ✅ | `undefined` | `undefined` | `undefined` |
|
|
62
|
+
|
|
63
|
+
> [!NOTE]
|
|
64
|
+
> On Apple, email/name can be limited after first consent depending on Apple policy.
|
|
34
65
|
|
|
35
66
|
## Installation
|
|
36
67
|
|
|
37
68
|
```bash
|
|
38
69
|
bun add react-native-nitro-auth react-native-nitro-modules
|
|
39
|
-
# or
|
|
40
|
-
npm install react-native-nitro-auth react-native-nitro-modules
|
|
41
|
-
# or
|
|
42
|
-
yarn add react-native-nitro-auth react-native-nitro-modules
|
|
43
|
-
# or
|
|
44
|
-
pnpm add react-native-nitro-auth react-native-nitro-modules
|
|
45
70
|
```
|
|
46
71
|
|
|
72
|
+
### Requirements
|
|
73
|
+
|
|
74
|
+
| Dependency | Version |
|
|
75
|
+
| ---------------------------- | ----------- |
|
|
76
|
+
| `react-native` | `>= 0.75.0` |
|
|
77
|
+
| `react-native-nitro-modules` | `>= 0.33.9` |
|
|
78
|
+
| `react` | `*` |
|
|
79
|
+
|
|
47
80
|
For Expo projects, rebuild native code after installation:
|
|
48
81
|
|
|
49
82
|
```bash
|
|
@@ -58,37 +91,45 @@ Fastest way to confirm the package and Microsoft login work:
|
|
|
58
91
|
In [Azure Portal](https://portal.azure.com) → **Azure Active Directory** → **App registrations** → **New registration**:
|
|
59
92
|
- Name: e.g. `Nitro Auth Example`
|
|
60
93
|
- Supported account types: **Accounts in any organizational directory and personal Microsoft accounts**
|
|
61
|
-
- Redirect URI (add after creation):
|
|
62
|
-
- **Android**: `msauth://com.auth.example/<client-id>`
|
|
94
|
+
- Redirect URI (add after creation):
|
|
95
|
+
- **Android**: `msauth://com.auth.example/<client-id>`
|
|
63
96
|
- **iOS**: `msauth.com.auth.example://auth` (use your bundle id)
|
|
64
97
|
- Under **Authentication** → **Platform configurations** → add **Mobile and desktop applications** with the Android redirect URI above and the iOS one if testing on iOS.
|
|
65
|
-
|
|
98
|
+
Copy the **Application (client) ID**.
|
|
66
99
|
|
|
67
100
|
2. **Env file**
|
|
68
101
|
From the repo root:
|
|
102
|
+
|
|
69
103
|
```bash
|
|
70
104
|
cd apps/example
|
|
71
105
|
cp .env.example .env.local
|
|
72
106
|
```
|
|
107
|
+
|
|
73
108
|
Edit `.env.local` and set at least:
|
|
109
|
+
|
|
74
110
|
```bash
|
|
75
111
|
MICROSOFT_CLIENT_ID=<your-application-client-id>
|
|
76
112
|
MICROSOFT_TENANT=common
|
|
77
113
|
```
|
|
114
|
+
|
|
78
115
|
(Google/Apple can stay placeholder if you only care about Microsoft.)
|
|
79
116
|
|
|
80
117
|
3. **Run the app**
|
|
81
118
|
From the **monorepo root**:
|
|
119
|
+
|
|
82
120
|
```bash
|
|
83
121
|
bun install
|
|
84
122
|
bun run start
|
|
85
123
|
```
|
|
124
|
+
|
|
86
125
|
In a second terminal:
|
|
126
|
+
|
|
87
127
|
```bash
|
|
88
128
|
bun run example:android
|
|
89
129
|
# or
|
|
90
130
|
bun run example:ios
|
|
91
131
|
```
|
|
132
|
+
|
|
92
133
|
Wait for the app to install and open.
|
|
93
134
|
|
|
94
135
|
4. **Test Microsoft**
|
|
@@ -297,7 +338,9 @@ Nitro Auth reads web configuration from `expo.extra`:
|
|
|
297
338
|
"microsoftClientId": "YOUR_AZURE_AD_CLIENT_ID",
|
|
298
339
|
"microsoftTenant": "common",
|
|
299
340
|
"microsoftB2cDomain": "your-tenant.b2clogin.com",
|
|
300
|
-
"appleWebClientId": "com.example.web"
|
|
341
|
+
"appleWebClientId": "com.example.web",
|
|
342
|
+
"nitroAuthWebStorage": "session",
|
|
343
|
+
"nitroAuthPersistTokensOnWeb": false
|
|
301
344
|
}
|
|
302
345
|
}
|
|
303
346
|
}
|
|
@@ -305,6 +348,9 @@ Nitro Auth reads web configuration from `expo.extra`:
|
|
|
305
348
|
|
|
306
349
|
For Apple web sign-in, `appleWebClientId` must be your Apple Service ID. For Microsoft web, make sure your Azure app includes a Web redirect URI matching your site.
|
|
307
350
|
|
|
351
|
+
- `nitroAuthWebStorage`: `"session"` (default), `"local"`, or `"memory"`.
|
|
352
|
+
- `nitroAuthPersistTokensOnWeb`: `false` by default (recommended). Set `true` only if you need cross-reload token persistence.
|
|
353
|
+
|
|
308
354
|
## Quick Start
|
|
309
355
|
|
|
310
356
|
### Using the Hook
|
|
@@ -453,7 +499,11 @@ If you previously called `GoogleSignin.configure()` at app startup, remove it. N
|
|
|
453
499
|
|
|
454
500
|
### Silent Restore
|
|
455
501
|
|
|
456
|
-
|
|
502
|
+
Attempts to restore provider SDK sessions on app startup.
|
|
503
|
+
|
|
504
|
+
- Google: restore is supported via provider SDK session state.
|
|
505
|
+
- Apple: provider credentials are re-requested by OS flow.
|
|
506
|
+
- Microsoft: no internal persistence; restore requires your app/backend session strategy.
|
|
457
507
|
|
|
458
508
|
```tsx
|
|
459
509
|
useEffect(() => {
|
|
@@ -510,56 +560,90 @@ const handleCalendar = async () => {
|
|
|
510
560
|
};
|
|
511
561
|
```
|
|
512
562
|
|
|
513
|
-
###
|
|
514
|
-
|
|
515
|
-
Nitro Auth persists the session automatically. By default, it uses secure storage on native (Keychain on iOS, EncryptedSharedPreferences on Android) and `localStorage` on web.
|
|
563
|
+
### App-Owned Persistence
|
|
516
564
|
|
|
517
|
-
|
|
565
|
+
Nitro Auth is intentionally stateless in-process. Persist only what your app needs.
|
|
518
566
|
|
|
519
|
-
|
|
567
|
+
#### Using react-native-nitro-storage (Recommended)
|
|
520
568
|
|
|
521
569
|
```ts
|
|
522
|
-
import { AuthService, type
|
|
523
|
-
import {
|
|
570
|
+
import { AuthService, type AuthUser } from "react-native-nitro-auth";
|
|
571
|
+
import { createStorageItem, StorageScope } from "react-native-nitro-storage";
|
|
524
572
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
load: (key) => storage.getString(key),
|
|
530
|
-
remove: (key) => storage.delete(key),
|
|
573
|
+
type AuthSnapshot = {
|
|
574
|
+
user: AuthUser | undefined;
|
|
575
|
+
scopes: string[];
|
|
576
|
+
updatedAt: number | undefined;
|
|
531
577
|
};
|
|
532
578
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
579
|
+
const authSnapshotItem = createStorageItem<AuthSnapshot>({
|
|
580
|
+
key: "auth_snapshot",
|
|
581
|
+
scope: StorageScope.Disk,
|
|
582
|
+
defaultValue: {
|
|
583
|
+
user: undefined,
|
|
584
|
+
scopes: [],
|
|
585
|
+
updatedAt: undefined,
|
|
586
|
+
},
|
|
587
|
+
});
|
|
539
588
|
|
|
540
|
-
|
|
589
|
+
// Save on auth changes (do not overwrite snapshot with empty user on app refresh)
|
|
590
|
+
AuthService.onAuthStateChanged((user) => {
|
|
591
|
+
if (!user) return;
|
|
541
592
|
|
|
542
|
-
|
|
593
|
+
authSnapshotItem.set({
|
|
594
|
+
user,
|
|
595
|
+
scopes: AuthService.grantedScopes,
|
|
596
|
+
updatedAt: Date.now(),
|
|
597
|
+
});
|
|
598
|
+
});
|
|
543
599
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
600
|
+
// Keep token/expiration fields fresh in persisted snapshot
|
|
601
|
+
AuthService.onTokensRefreshed((tokens) => {
|
|
602
|
+
authSnapshotItem.set((prev) => {
|
|
603
|
+
if (!prev.user) return prev;
|
|
604
|
+
|
|
605
|
+
return {
|
|
606
|
+
...prev,
|
|
607
|
+
user: {
|
|
608
|
+
...prev.user,
|
|
609
|
+
accessToken: tokens.accessToken ?? prev.user.accessToken,
|
|
610
|
+
idToken: tokens.idToken ?? prev.user.idToken,
|
|
611
|
+
refreshToken: tokens.refreshToken ?? prev.user.refreshToken,
|
|
612
|
+
expirationTime: tokens.expirationTime ?? prev.user.expirationTime,
|
|
613
|
+
},
|
|
614
|
+
updatedAt: Date.now(),
|
|
615
|
+
};
|
|
616
|
+
});
|
|
617
|
+
});
|
|
548
618
|
|
|
549
|
-
|
|
619
|
+
// Clear on logout
|
|
620
|
+
function logout() {
|
|
621
|
+
AuthService.logout();
|
|
622
|
+
authSnapshotItem.set({
|
|
623
|
+
user: undefined,
|
|
624
|
+
scopes: [],
|
|
625
|
+
updatedAt: undefined,
|
|
626
|
+
});
|
|
627
|
+
}
|
|
550
628
|
```
|
|
551
629
|
|
|
552
|
-
**Production recommendation:** If you need custom storage policies, auditability, or a different encryption model, provide your own adapter (Keychain, EncryptedSharedPreferences, or a secure JS store). See [Pluggable Storage Adapters](#pluggable-storage-adapters) above.
|
|
553
|
-
|
|
554
630
|
### Production Readiness
|
|
555
631
|
|
|
556
|
-
Nitro Auth is suitable for production use:
|
|
632
|
+
Nitro Auth is suitable for production use when configured with provider-accurate expectations:
|
|
557
633
|
|
|
558
|
-
- **Google Sign-In**:
|
|
559
|
-
- **Apple Sign-In**:
|
|
560
|
-
- **Microsoft (Azure AD / B2C)**:
|
|
634
|
+
- **Google Sign-In**: One-Tap + legacy on Android, native on iOS, popup on web.
|
|
635
|
+
- **Apple Sign-In**: iOS + web only.
|
|
636
|
+
- **Microsoft (Azure AD / B2C)**: iOS, Android, and web with PKCE/state/nonce protections.
|
|
561
637
|
|
|
562
|
-
|
|
638
|
+
Production checklist:
|
|
639
|
+
|
|
640
|
+
1. Configure client IDs, URL schemes, and redirect URIs per platform/provider.
|
|
641
|
+
2. Call `silentRestore()` during app startup to rehydrate provider session state when available.
|
|
642
|
+
3. Persist only app-owned snapshots/tokens (for example with `react-native-nitro-storage`), then clear them on logout.
|
|
643
|
+
4. On Android Google, use `useLegacyGoogleSignIn: true` when backend flows require `serverAuthCode`.
|
|
644
|
+
5. Treat token fields as optional and branch by provider/flow.
|
|
645
|
+
6. Keep web sensitive tokens memory-only unless you explicitly require persistent web tokens (`nitroAuthPersistTokensOnWeb: true`).
|
|
646
|
+
7. Enable logging only in development, and monitor normalized error codes in production.
|
|
563
647
|
|
|
564
648
|
### Logging & Debugging
|
|
565
649
|
|
|
@@ -571,9 +655,9 @@ import { AuthService } from "react-native-nitro-auth";
|
|
|
571
655
|
AuthService.setLoggingEnabled(true);
|
|
572
656
|
```
|
|
573
657
|
|
|
574
|
-
### Sync
|
|
658
|
+
### Sync State + Async Tokens
|
|
575
659
|
|
|
576
|
-
Nitro Auth provides synchronous access to
|
|
660
|
+
Nitro Auth provides synchronous access to in-memory state, while token retrieval remains async:
|
|
577
661
|
|
|
578
662
|
```ts
|
|
579
663
|
// Quick access to what we have in memory
|
|
@@ -617,7 +701,7 @@ try {
|
|
|
617
701
|
|
|
618
702
|
### Native Error Metadata
|
|
619
703
|
|
|
620
|
-
For more detailed debugging, Nitro Auth captures
|
|
704
|
+
For more detailed debugging, Nitro Auth captures raw provider/native details in `underlyingError` where available:
|
|
621
705
|
|
|
622
706
|
```ts
|
|
623
707
|
// From authenticated user (on success)
|
|
@@ -666,54 +750,6 @@ if (user?.serverAuthCode) {
|
|
|
666
750
|
}
|
|
667
751
|
```
|
|
668
752
|
|
|
669
|
-
### Custom Storage Adapter
|
|
670
|
-
|
|
671
|
-
By default, Nitro Auth uses secure native storage on iOS/Android and `localStorage` on web. You can provide a custom adapter for different security or storage requirements.
|
|
672
|
-
|
|
673
|
-
> [!IMPORTANT]
|
|
674
|
-
> `AuthStorageAdapter` must be implemented as a **native Nitro HybridObject** in C++, Swift, or Kotlin. Plain JavaScript objects are not supported due to Nitro's type system. See [Nitro Hybrid Objects documentation](https://nitro.margelo.com/docs/hybrid-objects) for implementation details.
|
|
675
|
-
|
|
676
|
-
**Example (Swift):**
|
|
677
|
-
|
|
678
|
-
```swift
|
|
679
|
-
class HybridKeychainStorage: HybridAuthStorageAdapterSpec {
|
|
680
|
-
func save(key: String, value: String) {
|
|
681
|
-
// Save to Keychain
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
func load(key: String) -> String? {
|
|
685
|
-
// Load from Keychain
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
func remove(key: String) {
|
|
689
|
-
// Remove from Keychain
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
```
|
|
693
|
-
|
|
694
|
-
**Usage (TypeScript):**
|
|
695
|
-
|
|
696
|
-
```ts
|
|
697
|
-
import { NitroModules } from "react-native-nitro-modules";
|
|
698
|
-
import { AuthService, AuthStorageAdapter } from "react-native-nitro-auth";
|
|
699
|
-
|
|
700
|
-
const keychainStorage =
|
|
701
|
-
NitroModules.createHybridObject<AuthStorageAdapter>("KeychainStorage");
|
|
702
|
-
AuthService.setStorageAdapter(keychainStorage);
|
|
703
|
-
```
|
|
704
|
-
|
|
705
|
-
### Token Refresh Listeners
|
|
706
|
-
|
|
707
|
-
Perfect for updating your API client (e.g., Axios/Fetch) whenever tokens are refreshed in the background:
|
|
708
|
-
|
|
709
|
-
```ts
|
|
710
|
-
AuthService.onTokensRefreshed((tokens) => {
|
|
711
|
-
console.log("Tokens were updated!", tokens.accessToken);
|
|
712
|
-
apiClient.defaults.headers.common["Authorization"] =
|
|
713
|
-
`Bearer ${tokens.accessToken}`;
|
|
714
|
-
});
|
|
715
|
-
```
|
|
716
|
-
|
|
717
753
|
### Google One-Tap & Sheet
|
|
718
754
|
|
|
719
755
|
Explicitly enable the modern One-Tap flow on Android or the Sign-In Sheet on iOS:
|
|
@@ -756,95 +792,231 @@ This is useful for scenarios where:
|
|
|
756
792
|
|
|
757
793
|
## API Reference
|
|
758
794
|
|
|
759
|
-
###
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
###
|
|
777
|
-
|
|
778
|
-
|
|
|
779
|
-
|
|
|
780
|
-
| `
|
|
781
|
-
| `
|
|
782
|
-
| `
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
|
787
|
-
|
|
|
788
|
-
| `
|
|
789
|
-
| `
|
|
790
|
-
| `
|
|
791
|
-
| `
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
|
796
|
-
|
|
|
797
|
-
| `
|
|
798
|
-
| `
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
|
806
|
-
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
|
815
|
-
|
|
|
816
|
-
| `
|
|
817
|
-
| `
|
|
818
|
-
| `
|
|
819
|
-
| `
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
|
832
|
-
|
|
|
833
|
-
| `
|
|
795
|
+
### Package Exports
|
|
796
|
+
|
|
797
|
+
```ts
|
|
798
|
+
import {
|
|
799
|
+
AuthService,
|
|
800
|
+
SocialButton,
|
|
801
|
+
useAuth,
|
|
802
|
+
type UseAuthReturn,
|
|
803
|
+
type Auth,
|
|
804
|
+
type AuthUser,
|
|
805
|
+
type AuthTokens,
|
|
806
|
+
type AuthProvider,
|
|
807
|
+
type AuthErrorCode,
|
|
808
|
+
type LoginOptions,
|
|
809
|
+
} from "react-native-nitro-auth";
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
### Core Types
|
|
813
|
+
|
|
814
|
+
| Type | Definition |
|
|
815
|
+
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
816
|
+
| `AuthProvider` | `"google" \| "apple" \| "microsoft"` |
|
|
817
|
+
| `AuthErrorCode` | `"cancelled" \| "timeout" \| "popup_blocked" \| "network_error" \| "configuration_error" \| "unsupported_provider" \| "invalid_state" \| "invalid_nonce" \| "token_error" \| "no_id_token" \| "parse_error" \| "refresh_failed" \| "unknown"` |
|
|
818
|
+
| `MicrosoftPrompt` | `"login" \| "consent" \| "select_account" \| "none"` |
|
|
819
|
+
|
|
820
|
+
### `AuthUser`
|
|
821
|
+
|
|
822
|
+
| Field | Type | Description |
|
|
823
|
+
| ----------------- | ----------------------- | -------------------------------------------------------------------------- |
|
|
824
|
+
| `provider` | `AuthProvider` | Provider that authenticated the user |
|
|
825
|
+
| `email` | `string \| undefined` | User email |
|
|
826
|
+
| `name` | `string \| undefined` | Display name |
|
|
827
|
+
| `photo` | `string \| undefined` | Profile image URL (Google) |
|
|
828
|
+
| `idToken` | `string \| undefined` | OIDC ID token |
|
|
829
|
+
| `accessToken` | `string \| undefined` | OAuth access token |
|
|
830
|
+
| `refreshToken` | `string \| undefined` | OAuth refresh token |
|
|
831
|
+
| `serverAuthCode` | `string \| undefined` | Google server auth code (legacy Android flow + backend exchange scenarios) |
|
|
832
|
+
| `scopes` | `string[] \| undefined` | Granted scopes for current session |
|
|
833
|
+
| `expirationTime` | `number \| undefined` | Expiration timestamp in milliseconds since epoch |
|
|
834
|
+
| `underlyingError` | `string \| undefined` | Raw provider/native error message |
|
|
835
|
+
|
|
836
|
+
> [!NOTE]
|
|
837
|
+
> On Android Google One-Tap/Credential Manager, `idToken` is typically available immediately, while `accessToken` and `expirationTime` may be `undefined` until refresh/exchange flow provides them.
|
|
838
|
+
|
|
839
|
+
### `AuthTokens`
|
|
840
|
+
|
|
841
|
+
| Field | Type | Description |
|
|
842
|
+
| ---------------- | --------------------- | ----------------------------- |
|
|
843
|
+
| `accessToken` | `string \| undefined` | Refreshed access token |
|
|
844
|
+
| `idToken` | `string \| undefined` | Refreshed ID token |
|
|
845
|
+
| `refreshToken` | `string \| undefined` | Refresh token (if available) |
|
|
846
|
+
| `expirationTime` | `number \| undefined` | Optional expiration timestamp |
|
|
847
|
+
|
|
848
|
+
### `LoginOptions`
|
|
849
|
+
|
|
850
|
+
| Option | Type | Platform | Description |
|
|
851
|
+
| ----------------------- | ----------------- | --------- | --------------------------------------------------------------------------------- |
|
|
852
|
+
| `scopes` | `string[]` | All | Requested scopes (defaults are provider-specific) |
|
|
853
|
+
| `loginHint` | `string` | All | Prefills account identifier |
|
|
854
|
+
| `useOneTap` | `boolean` | Android | Use Credential Manager/One-Tap flow |
|
|
855
|
+
| `useSheet` | `boolean` | iOS | Use native Google Sign-In sheet |
|
|
856
|
+
| `forceAccountPicker` | `boolean` | All | Always show account chooser |
|
|
857
|
+
| `useLegacyGoogleSignIn` | `boolean` | Android | Use legacy Google Sign-In (required when you need `serverAuthCode`) |
|
|
858
|
+
| `tenant` | `string` | Microsoft | Tenant (`common`, `organizations`, `consumers`, tenant id, or full authority URL) |
|
|
859
|
+
| `prompt` | `MicrosoftPrompt` | Microsoft | Prompt behavior |
|
|
860
|
+
|
|
861
|
+
### `useAuth()`
|
|
862
|
+
|
|
863
|
+
```ts
|
|
864
|
+
declare function useAuth(): UseAuthReturn;
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
| Property | Type | Description |
|
|
868
|
+
| ----------------- | ------------------------------------------------------------------- | ---------------------------------------------------- |
|
|
869
|
+
| `user` | `AuthUser \| undefined` | Current in-memory user |
|
|
870
|
+
| `scopes` | `string[]` | Current granted scopes |
|
|
871
|
+
| `loading` | `boolean` | `true` while an auth operation is in-flight |
|
|
872
|
+
| `error` | `Error \| undefined` | Last operation error |
|
|
873
|
+
| `hasPlayServices` | `boolean` | Android Play Services availability |
|
|
874
|
+
| `login` | `(provider: AuthProvider, options?: LoginOptions) => Promise<void>` | Starts provider login |
|
|
875
|
+
| `logout` | `() => void` | Clears current session |
|
|
876
|
+
| `requestScopes` | `(scopes: string[]) => Promise<void>` | Requests additional scopes |
|
|
877
|
+
| `revokeScopes` | `(scopes: string[]) => Promise<void>` | Revokes scopes in current session |
|
|
878
|
+
| `getAccessToken` | `() => Promise<string \| undefined>` | Returns access token, auto-refreshing when supported |
|
|
879
|
+
| `refreshToken` | `() => Promise<AuthTokens>` | Explicit refresh |
|
|
880
|
+
| `silentRestore` | `() => Promise<void>` | Restores provider SDK session (if available) |
|
|
881
|
+
|
|
882
|
+
### `AuthService`
|
|
883
|
+
|
|
884
|
+
Synchronous state + async operations (useful outside React trees).
|
|
885
|
+
|
|
886
|
+
#### Readonly state
|
|
887
|
+
|
|
888
|
+
| Property | Type | Description |
|
|
889
|
+
| ----------------- | ----------------------- | ---------------------------------- |
|
|
890
|
+
| `name` | `string` | Hybrid object name (`"Auth"`) |
|
|
891
|
+
| `currentUser` | `AuthUser \| undefined` | Current user snapshot |
|
|
892
|
+
| `grantedScopes` | `string[]` | Current scope snapshot |
|
|
893
|
+
| `hasPlayServices` | `boolean` | Android Play Services availability |
|
|
894
|
+
|
|
895
|
+
#### Methods
|
|
896
|
+
|
|
897
|
+
| Method | Signature | Description |
|
|
898
|
+
| -------------------- | -------------------------------------------------------- | -------------------------------- |
|
|
899
|
+
| `login` | `(provider, options?) => Promise<void>` | Starts login |
|
|
900
|
+
| `logout` | `() => void` | Clears session |
|
|
901
|
+
| `requestScopes` | `(scopes) => Promise<void>` | Incremental auth |
|
|
902
|
+
| `revokeScopes` | `(scopes) => Promise<void>` | Scope revoke |
|
|
903
|
+
| `getAccessToken` | `() => Promise<string \| undefined>` | Access token getter with refresh |
|
|
904
|
+
| `refreshToken` | `() => Promise<AuthTokens>` | Explicit token refresh |
|
|
905
|
+
| `silentRestore` | `() => Promise<void>` | Restore provider SDK session |
|
|
906
|
+
| `onAuthStateChanged` | `(callback: (user?: AuthUser) => void) => () => void` | Auth change listener |
|
|
907
|
+
| `onTokensRefreshed` | `(callback: (tokens: AuthTokens) => void) => () => void` | Token refresh listener |
|
|
908
|
+
| `setLoggingEnabled` | `(enabled: boolean) => void` | Debug logging toggle |
|
|
909
|
+
| `dispose` | `() => void` | Disposes hybrid object |
|
|
910
|
+
| `equals` | `(other: unknown) => boolean` | Hybrid object identity check |
|
|
911
|
+
|
|
912
|
+
### Storage Contract
|
|
913
|
+
|
|
914
|
+
Nitro Auth does not provide persistence APIs. Persist the auth data you need in your app layer (for example with `react-native-nitro-storage`, MMKV, Keychain wrappers, or backend-issued sessions).
|
|
915
|
+
There is no public `setStorageAdapter`/`setJSStorageAdapter` API in this package.
|
|
916
|
+
|
|
917
|
+
### `SocialButton`
|
|
918
|
+
|
|
919
|
+
| Prop | Type | Default | Description |
|
|
920
|
+
| -------------- | ---------------------------------------------- | ----------- | ------------------------------------------- |
|
|
921
|
+
| `provider` | `AuthProvider` | required | Provider |
|
|
922
|
+
| `variant` | `"primary" \| "outline" \| "white" \| "black"` | `"primary"` | Visual style |
|
|
923
|
+
| `borderRadius` | `number` | `8` | Border radius |
|
|
924
|
+
| `style` | `ViewStyle` | `undefined` | Container style override |
|
|
925
|
+
| `textStyle` | `TextStyle` | `undefined` | Text style override |
|
|
926
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
927
|
+
| `onPress` | `() => void` | `undefined` | Custom press handler (skips built-in login) |
|
|
928
|
+
| `onSuccess` | `(user: AuthUser) => void` | `undefined` | Called after successful default login |
|
|
929
|
+
| `onError` | `(error: unknown) => void` | `undefined` | Called when default login fails |
|
|
930
|
+
|
|
931
|
+
### Config Plugin API (`app.json` / `app.config.js`)
|
|
932
|
+
|
|
933
|
+
`plugins: [["react-native-nitro-auth", { ios: {...}, android: {...} }]]`
|
|
934
|
+
|
|
935
|
+
#### iOS plugin options
|
|
936
|
+
|
|
937
|
+
| Option | Type | Description |
|
|
938
|
+
| ---------------------- | --------- | -------------------------------------------- |
|
|
939
|
+
| `googleClientId` | `string` | Writes `GIDClientID` |
|
|
940
|
+
| `googleServerClientId` | `string` | Writes `GIDServerClientID` |
|
|
941
|
+
| `googleUrlScheme` | `string` | Adds Google URL scheme |
|
|
942
|
+
| `appleSignIn` | `boolean` | Enables Apple Sign-In entitlement |
|
|
943
|
+
| `microsoftClientId` | `string` | Writes `MSALClientID` + MSAL redirect scheme |
|
|
944
|
+
| `microsoftTenant` | `string` | Writes `MSALTenant` |
|
|
945
|
+
| `microsoftB2cDomain` | `string` | Writes `MSALB2cDomain` |
|
|
946
|
+
|
|
947
|
+
#### Android plugin options
|
|
948
|
+
|
|
949
|
+
| Option | Type | Description |
|
|
950
|
+
| -------------------- | -------- | ---------------------------------------------------------------- |
|
|
951
|
+
| `googleClientId` | `string` | Writes `nitro_auth_google_client_id` string |
|
|
952
|
+
| `microsoftClientId` | `string` | Writes `nitro_auth_microsoft_client_id` + redirect intent filter |
|
|
953
|
+
| `microsoftTenant` | `string` | Writes `nitro_auth_microsoft_tenant` |
|
|
954
|
+
| `microsoftB2cDomain` | `string` | Writes `nitro_auth_microsoft_b2c_domain` |
|
|
955
|
+
|
|
956
|
+
### Web runtime config (`expo.extra`)
|
|
957
|
+
|
|
958
|
+
| Key | Type | Default | Description |
|
|
959
|
+
| ----------------------------- | ---------------------------------- | ----------- | --------------------------------------------------------- |
|
|
960
|
+
| `googleWebClientId` | `string` | `undefined` | Google web OAuth client id |
|
|
961
|
+
| `microsoftClientId` | `string` | `undefined` | Microsoft app client id |
|
|
962
|
+
| `microsoftTenant` | `string` | `"common"` | Microsoft tenant/authority |
|
|
963
|
+
| `microsoftB2cDomain` | `string` | `undefined` | B2C domain when applicable |
|
|
964
|
+
| `appleWebClientId` | `string` | `undefined` | Apple Service ID |
|
|
965
|
+
| `nitroAuthWebStorage` | `"session" \| "local" \| "memory"` | `"session"` | Storage for non-sensitive web cache |
|
|
966
|
+
| `nitroAuthPersistTokensOnWeb` | `boolean` | `false` | Persist sensitive tokens on web storage instead of memory |
|
|
967
|
+
|
|
968
|
+
### Error semantics
|
|
969
|
+
|
|
970
|
+
Errors are surfaced as `Error` with `message` as a normalized code when possible, and `underlyingError` with provider/native details.
|
|
971
|
+
|
|
972
|
+
| Normalized message | Meaning |
|
|
973
|
+
| --------------------- | ---------------------------------------------- |
|
|
974
|
+
| `cancelled` | User cancelled popup/login flow |
|
|
975
|
+
| `timeout` | Provider popup did not complete before timeout |
|
|
976
|
+
| `popup_blocked` | Browser blocked popup opening |
|
|
977
|
+
| `network_error` | Network failure |
|
|
978
|
+
| `configuration_error` | Missing/invalid provider configuration |
|
|
979
|
+
|
|
980
|
+
## Quality Gates
|
|
981
|
+
|
|
982
|
+
From monorepo root:
|
|
983
|
+
|
|
984
|
+
```bash
|
|
985
|
+
bun run format:check
|
|
986
|
+
bun run lint
|
|
987
|
+
bun run typecheck
|
|
988
|
+
```
|
|
989
|
+
|
|
990
|
+
Workspace-local commands:
|
|
991
|
+
|
|
992
|
+
```bash
|
|
993
|
+
# apps/example
|
|
994
|
+
bun run format
|
|
995
|
+
bun run lint
|
|
996
|
+
bun run typecheck
|
|
997
|
+
|
|
998
|
+
# packages/react-native-nitro-auth
|
|
999
|
+
bun run format
|
|
1000
|
+
bun run lint
|
|
1001
|
+
bun run typecheck
|
|
1002
|
+
bun run test
|
|
1003
|
+
```
|
|
834
1004
|
|
|
835
1005
|
## Platform Support
|
|
836
1006
|
|
|
837
|
-
| Feature
|
|
838
|
-
|
|
|
839
|
-
| Google Sign-In
|
|
840
|
-
| Apple Sign-In
|
|
841
|
-
| Microsoft Sign-In
|
|
842
|
-
| Custom OAuth Scopes
|
|
843
|
-
| Incremental Authorization
|
|
844
|
-
| Token Refresh
|
|
845
|
-
| Session Persistence
|
|
846
|
-
|
|
|
847
|
-
|
|
|
1007
|
+
| Feature | iOS | Android | Web |
|
|
1008
|
+
| -------------------------- | --- | ------- | --- |
|
|
1009
|
+
| Google Sign-In | ✅ | ✅ | ✅ |
|
|
1010
|
+
| Apple Sign-In | ✅ | ❌ | ✅ |
|
|
1011
|
+
| Microsoft Sign-In | ✅ | ✅ | ✅ |
|
|
1012
|
+
| Custom OAuth Scopes | ✅ | ✅ | ✅ |
|
|
1013
|
+
| Incremental Authorization | ✅ | ✅ | ✅ |
|
|
1014
|
+
| Token Refresh | ✅ | ✅ | ✅ |
|
|
1015
|
+
| Native Session Persistence | ❌ | ❌ | — |
|
|
1016
|
+
| Web Auth Snapshot Cache | — | — | ✅ |
|
|
1017
|
+
| App-Owned Persistence | ✅ | ✅ | ✅ |
|
|
1018
|
+
| Auto-Refresh | ✅ | ✅ | ✅ |
|
|
1019
|
+
| Native C++ Performance | ✅ | ✅ | — |
|
|
848
1020
|
|
|
849
1021
|
## Architecture
|
|
850
1022
|
|