react-native-nitro-auth 0.5.7 → 0.5.9
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 +33 -0
- package/README.md +295 -906
- package/android/src/main/java/com/auth/AuthAdapter.kt +22 -6
- package/cpp/HybridAuth.cpp +175 -39
- package/cpp/HybridAuth.hpp +2 -0
- package/ios/AuthAdapter.swift +2 -2
- package/lib/commonjs/Auth.web.js +141 -73
- package/lib/commonjs/Auth.web.js.map +1 -1
- package/lib/commonjs/create-auth-service.js +71 -0
- package/lib/commonjs/create-auth-service.js.map +1 -0
- package/lib/commonjs/service.js +2 -79
- package/lib/commonjs/service.js.map +1 -1
- package/lib/commonjs/service.web.js +2 -79
- package/lib/commonjs/service.web.js.map +1 -1
- package/lib/commonjs/use-auth.js +6 -3
- package/lib/commonjs/use-auth.js.map +1 -1
- package/lib/commonjs/utils/auth-error.js +8 -1
- package/lib/commonjs/utils/auth-error.js.map +1 -1
- package/lib/module/Auth.web.js +141 -73
- package/lib/module/Auth.web.js.map +1 -1
- package/lib/module/create-auth-service.js +67 -0
- package/lib/module/create-auth-service.js.map +1 -0
- package/lib/module/service.js +2 -79
- package/lib/module/service.js.map +1 -1
- package/lib/module/service.web.js +2 -79
- package/lib/module/service.web.js.map +1 -1
- package/lib/module/use-auth.js +6 -3
- package/lib/module/use-auth.js.map +1 -1
- package/lib/module/utils/auth-error.js +8 -1
- package/lib/module/utils/auth-error.js.map +1 -1
- package/lib/typescript/commonjs/Auth.web.d.ts +4 -2
- package/lib/typescript/commonjs/Auth.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/create-auth-service.d.ts +5 -0
- package/lib/typescript/commonjs/create-auth-service.d.ts.map +1 -0
- package/lib/typescript/commonjs/service.d.ts.map +1 -1
- package/lib/typescript/commonjs/service.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/use-auth.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/auth-error.d.ts.map +1 -1
- package/lib/typescript/module/Auth.web.d.ts +4 -2
- package/lib/typescript/module/Auth.web.d.ts.map +1 -1
- package/lib/typescript/module/create-auth-service.d.ts +5 -0
- package/lib/typescript/module/create-auth-service.d.ts.map +1 -0
- package/lib/typescript/module/service.d.ts.map +1 -1
- package/lib/typescript/module/service.web.d.ts.map +1 -1
- package/lib/typescript/module/use-auth.d.ts.map +1 -1
- package/lib/typescript/module/utils/auth-error.d.ts.map +1 -1
- package/package.json +12 -9
- package/react-native-nitro-auth.podspec +1 -0
- package/src/Auth.web.ts +261 -102
- package/src/create-auth-service.ts +97 -0
- package/src/service.ts +3 -101
- package/src/service.web.ts +3 -101
- package/src/use-auth.ts +7 -3
- package/src/utils/auth-error.ts +10 -1
package/README.md
CHANGED
|
@@ -1,213 +1,71 @@
|
|
|
1
1
|
# react-native-nitro-auth
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://nitro.margelo.com)
|
|
3
|
+
Fast React Native authentication for Google Sign-In, Apple Sign-In, and Microsoft Entra ID, built on Nitro Modules and JSI.
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
`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.
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
## Why Use It?
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
- One package for Google, Apple, and Microsoft authentication on React Native.
|
|
10
|
+
- Native iOS and Android bridges powered by `react-native-nitro-modules`.
|
|
11
|
+
- Expo config plugin for client IDs, URL schemes, entitlements, and Android resources.
|
|
12
|
+
- Web implementation for Expo web with Google, Apple, and Microsoft OAuth.
|
|
13
|
+
- Typed `useAuth()` hook, `AuthService`, `SocialButton`, and `AuthError`.
|
|
14
|
+
- App-owned persistence model: tokens stay in memory unless your app stores a snapshot.
|
|
15
|
+
- Built-in flows for silent restore, token refresh, account picker, login hints, and incremental Google scopes.
|
|
16
|
+
- Consistent `AuthError` mapping for async `AuthService` failures on native and web.
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
## Choose Your Path
|
|
14
19
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
| **Provider Data** | Varies | **Normalized auth payload** |
|
|
20
|
+
| Need | Use |
|
|
21
|
+
| ---------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
22
|
+
| Google, Apple, or Microsoft sign-in in an Expo or React Native app | `react-native-nitro-auth` |
|
|
23
|
+
| Generic OAuth or OIDC provider not covered by this package | `expo-auth-session` or `react-native-app-auth` |
|
|
24
|
+
| Firebase user management, password auth, MFA, and hosted auth platform | `@react-native-firebase/auth`, Auth0, Authgear, or your IDaaS SDK |
|
|
25
|
+
| Server-side session validation | Your backend; client JWT decode is display-only |
|
|
22
26
|
|
|
23
|
-
##
|
|
27
|
+
## Install
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
- **Fully Type-Safe**: Shared types between TypeScript, C++, Swift, and Kotlin.
|
|
27
|
-
- **Incremental Auth**: Request additional OAuth scopes on the fly.
|
|
28
|
-
- **Expo Ready**: Comes with a powerful Config Plugin for zero-config setup.
|
|
29
|
-
- **Cross-Platform**: Unified API for iOS, Android, and Web.
|
|
30
|
-
- **Token Lifecycle Helpers**: `getAccessToken()` refreshes near-expiry tokens; `refreshToken()` allows explicit refresh control.
|
|
31
|
-
- **Google One-Tap / Sheet**: Modern login experience on Android (Credential Manager) and iOS (Sign-In Sheet).
|
|
32
|
-
- **Error Metadata**: Detailed native error messages for easier debugging.
|
|
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.
|
|
65
|
-
|
|
66
|
-
## Installation
|
|
67
|
-
|
|
68
|
-
```bash
|
|
29
|
+
```sh
|
|
69
30
|
bun add react-native-nitro-auth react-native-nitro-modules
|
|
70
31
|
```
|
|
71
32
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
| Dependency | Version |
|
|
75
|
-
| ---------------------------- | ------------ |
|
|
76
|
-
| `react-native` | `>= 0.75.0` |
|
|
77
|
-
| `react-native-nitro-modules` | `>= 0.35.0` |
|
|
78
|
-
| `react` | `*` |
|
|
33
|
+
For Expo projects, prebuild after adding the config plugin:
|
|
79
34
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
bunx expo prebuild
|
|
35
|
+
```sh
|
|
36
|
+
bunx expo prebuild --clean
|
|
84
37
|
```
|
|
85
38
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
Fastest way to confirm the package and Microsoft login work:
|
|
89
|
-
|
|
90
|
-
1. **Azure app (one-time)**
|
|
91
|
-
In [Azure Portal](https://portal.azure.com) → **Azure Active Directory** → **App registrations** → **New registration**:
|
|
92
|
-
- Name: e.g. `Nitro Auth Example`
|
|
93
|
-
- Supported account types: **Accounts in any organizational directory and personal Microsoft accounts**
|
|
94
|
-
- Redirect URI (add after creation):
|
|
95
|
-
- **Android**: `msauth://com.auth.example/<client-id>`
|
|
96
|
-
- **iOS**: `msauth.com.auth.example://auth` (use your bundle id)
|
|
97
|
-
- Under **Authentication** → **Platform configurations** → add **Mobile and desktop applications** with the Android redirect URI above and the iOS one if testing on iOS.
|
|
98
|
-
Copy the **Application (client) ID**.
|
|
99
|
-
|
|
100
|
-
2. **Env file**
|
|
101
|
-
From the repo root:
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
cd apps/example
|
|
105
|
-
cp .env.example .env.local
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Edit `.env.local` and set at least:
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
MICROSOFT_CLIENT_ID=<your-application-client-id>
|
|
112
|
-
MICROSOFT_TENANT=common
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
(Google/Apple can stay placeholder if you only care about Microsoft.)
|
|
116
|
-
|
|
117
|
-
3. **Run the app**
|
|
118
|
-
From the **monorepo root**:
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
bun install
|
|
122
|
-
bun run start
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
In a second terminal:
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
bun run example:android
|
|
129
|
-
# or
|
|
130
|
-
bun run example:ios
|
|
131
|
-
```
|
|
39
|
+
For bare React Native projects, install pods after installing the package:
|
|
132
40
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
4. **Test Microsoft**
|
|
136
|
-
In the app, tap **Sign in with Microsoft**. A browser or in-app tab opens; sign in with a Microsoft/personal account, then you should return to the app with the user shown (email, name, provider MICROSOFT).
|
|
137
|
-
If you see "configuration_error", check `MICROSOFT_CLIENT_ID` and that the redirect URI in Azure matches your app (e.g. `msauth://com.auth.example/<client-id>` for the example app).
|
|
138
|
-
|
|
139
|
-
> [!TIP]
|
|
140
|
-
> In the example app on Android, you can toggle **Legacy Google Sign-In** to compare Credential Manager vs legacy GoogleSignIn (and to get `serverAuthCode`).
|
|
141
|
-
|
|
142
|
-
### Expo Setup
|
|
143
|
-
|
|
144
|
-
Add the plugin to `app.json` or `app.config.js`:
|
|
145
|
-
|
|
146
|
-
```json
|
|
147
|
-
{
|
|
148
|
-
"expo": {
|
|
149
|
-
"plugins": [
|
|
150
|
-
[
|
|
151
|
-
"react-native-nitro-auth",
|
|
152
|
-
{
|
|
153
|
-
"ios": {
|
|
154
|
-
"googleClientId": "YOUR_IOS_CLIENT_ID.apps.googleusercontent.com",
|
|
155
|
-
"googleServerClientId": "YOUR_WEB_CLIENT_ID.apps.googleusercontent.com",
|
|
156
|
-
"googleUrlScheme": "com.googleusercontent.apps.YOUR_IOS_CLIENT_ID",
|
|
157
|
-
"appleSignIn": true,
|
|
158
|
-
"microsoftClientId": "YOUR_AZURE_AD_CLIENT_ID",
|
|
159
|
-
"microsoftTenant": "common",
|
|
160
|
-
"microsoftB2cDomain": "your-tenant.b2clogin.com"
|
|
161
|
-
},
|
|
162
|
-
"android": {
|
|
163
|
-
"googleClientId": "YOUR_WEB_CLIENT_ID.apps.googleusercontent.com",
|
|
164
|
-
"microsoftClientId": "YOUR_AZURE_AD_CLIENT_ID",
|
|
165
|
-
"microsoftTenant": "common",
|
|
166
|
-
"microsoftB2cDomain": "your-tenant.b2clogin.com"
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
]
|
|
170
|
-
],
|
|
171
|
-
"extra": {
|
|
172
|
-
"googleWebClientId": "YOUR_WEB_CLIENT_ID.apps.googleusercontent.com",
|
|
173
|
-
"microsoftClientId": "YOUR_AZURE_AD_CLIENT_ID",
|
|
174
|
-
"microsoftTenant": "common",
|
|
175
|
-
"microsoftB2cDomain": "your-tenant.b2clogin.com",
|
|
176
|
-
"appleWebClientId": "com.example.web"
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
41
|
+
```sh
|
|
42
|
+
cd ios && pod install
|
|
180
43
|
```
|
|
181
44
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
Create a `.env.local` file:
|
|
185
|
-
|
|
186
|
-
```bash
|
|
187
|
-
# iOS Client ID
|
|
188
|
-
GOOGLE_IOS_CLIENT_ID=your-ios-client-id.apps.googleusercontent.com
|
|
189
|
-
GOOGLE_IOS_URL_SCHEME=com.googleusercontent.apps.your-ios-client-id
|
|
190
|
-
GOOGLE_SERVER_CLIENT_ID=your-web-client-id.apps.googleusercontent.com
|
|
45
|
+
## Requirements
|
|
191
46
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
# Apple (web only)
|
|
201
|
-
APPLE_WEB_CLIENT_ID=com.example.web
|
|
202
|
-
```
|
|
47
|
+
| Runtime | Requirement |
|
|
48
|
+
| --------------------- | ---------------------------------------- |
|
|
49
|
+
| React Native | `>=0.75` |
|
|
50
|
+
| Nitro Modules | `>=0.35` |
|
|
51
|
+
| iOS | 15.1+ recommended |
|
|
52
|
+
| Android | min SDK 24+ recommended |
|
|
53
|
+
| Expo example baseline | Expo SDK 55, React Native 0.83, React 19 |
|
|
203
54
|
|
|
204
|
-
|
|
55
|
+
## Expo Setup
|
|
205
56
|
|
|
206
|
-
|
|
207
|
-
import "dotenv/config";
|
|
57
|
+
Add the plugin to `app.json` or `app.config.js`.
|
|
208
58
|
|
|
59
|
+
```js
|
|
209
60
|
export default {
|
|
210
61
|
expo: {
|
|
62
|
+
scheme: "myapp",
|
|
63
|
+
ios: {
|
|
64
|
+
bundleIdentifier: "com.company.myapp",
|
|
65
|
+
},
|
|
66
|
+
android: {
|
|
67
|
+
package: "com.company.myapp",
|
|
68
|
+
},
|
|
211
69
|
plugins: [
|
|
212
70
|
[
|
|
213
71
|
"react-native-nitro-auth",
|
|
@@ -232,841 +90,372 @@ export default {
|
|
|
232
90
|
],
|
|
233
91
|
extra: {
|
|
234
92
|
googleWebClientId: process.env.GOOGLE_WEB_CLIENT_ID,
|
|
93
|
+
appleWebClientId: process.env.APPLE_WEB_CLIENT_ID,
|
|
235
94
|
microsoftClientId: process.env.MICROSOFT_CLIENT_ID,
|
|
236
95
|
microsoftTenant: process.env.MICROSOFT_TENANT,
|
|
237
96
|
microsoftB2cDomain: process.env.MICROSOFT_B2C_DOMAIN,
|
|
238
|
-
|
|
97
|
+
nitroAuthWebStorage: "memory",
|
|
98
|
+
nitroAuthPersistTokensOnWeb: false,
|
|
239
99
|
},
|
|
240
100
|
},
|
|
241
101
|
};
|
|
242
102
|
```
|
|
243
103
|
|
|
244
|
-
|
|
245
|
-
>
|
|
246
|
-
> - `appleSignIn` on iOS is `false` by default to avoid unnecessary entitlements. Set it to `true` to enable Apple Sign-In.
|
|
247
|
-
> - For Android, use your **Web Client ID** (not Android Client ID) for proper OAuth flow.
|
|
248
|
-
> - If you need `serverAuthCode`, set `googleServerClientId` to your Web Client ID.
|
|
249
|
-
> - Add `googleWebClientId` to `expo.extra` for web platform support.
|
|
250
|
-
> - The `serverAuthCode` is automatically included in `AuthUser` when available (requires backend integration setup in Google Cloud Console).
|
|
251
|
-
> - For Microsoft Sign-In, use `common` tenant for multi-tenant apps, or specify your Azure AD tenant ID for single-tenant apps.
|
|
252
|
-
> - For Azure AD B2C, set `microsoftB2cDomain` and pass the B2C tenant in `microsoftTenant`.
|
|
253
|
-
|
|
254
|
-
### Google OAuth Setup
|
|
255
|
-
|
|
256
|
-
1. Create OAuth client IDs in Google Cloud Console:
|
|
257
|
-
- **iOS client ID** (used by iOS)
|
|
258
|
-
- **Web client ID** (used by Android and for `serverAuthCode`)
|
|
259
|
-
2. Configure your app:
|
|
260
|
-
- Expo: set `googleClientId`, `googleServerClientId`, and `googleUrlScheme`
|
|
261
|
-
- Bare iOS: add `GIDClientID`, `GIDServerClientID`, and URL scheme in `Info.plist`
|
|
262
|
-
- Bare Android: set `nitro_auth_google_client_id` to your **Web client ID**
|
|
263
|
-
3. If you use `serverAuthCode`, make sure OAuth consent screen is configured in Google Cloud.
|
|
264
|
-
|
|
265
|
-
### Apple Sign-In Setup
|
|
266
|
-
|
|
267
|
-
1. **iOS**: enable the “Sign in with Apple” capability in Xcode and in your Apple Developer account.
|
|
268
|
-
2. **Web**: create a Service ID and configure the domain + return URL in Apple Developer.
|
|
269
|
-
3. Configure your app:
|
|
270
|
-
- Expo: set `appleSignIn: true` for iOS.
|
|
271
|
-
- Web: set `appleWebClientId` in `expo.extra` (or `.env`).
|
|
272
|
-
|
|
273
|
-
### Microsoft Azure AD Setup
|
|
274
|
-
|
|
275
|
-
To enable Microsoft Sign-In, you need to register an application in the Azure Portal:
|
|
276
|
-
|
|
277
|
-
1. Go to [Azure Portal](https://portal.azure.com) > Azure Active Directory > App registrations
|
|
278
|
-
2. Click "New registration"
|
|
279
|
-
3. Set the redirect URIs:
|
|
280
|
-
- **iOS**: `msauth.{bundle-identifier}://auth` (e.g., `msauth.com.myapp://auth`)
|
|
281
|
-
- **Android**: `msauth://{package-name}/{client-id}` (e.g., `msauth://com.myapp/00000000-0000-0000-0000-000000000000`)
|
|
282
|
-
- **Web**: `https://your-domain.com` (the page that loads the app)
|
|
283
|
-
4. Under "API permissions", add `openid`, `email`, `profile`, and `User.Read` (Microsoft Graph)
|
|
284
|
-
5. Copy the Application (client) ID for use in your config
|
|
285
|
-
|
|
286
|
-
**Tenant Options:**
|
|
287
|
-
|
|
288
|
-
- `common` - Any Azure AD or personal Microsoft account
|
|
289
|
-
- `organizations` - Any Azure AD account (work/school)
|
|
290
|
-
- `consumers` - Personal Microsoft accounts only
|
|
291
|
-
- `{tenant-id}` - Specific Azure AD tenant
|
|
292
|
-
- **B2C**: set `microsoftB2cDomain` (e.g. `your-tenant.b2clogin.com`) and use a tenant value like `your-tenant.onmicrosoft.com/B2C_1_signin` (or pass a full `https://.../` authority URL).
|
|
293
|
-
|
|
294
|
-
### Bare React Native
|
|
295
|
-
|
|
296
|
-
**iOS**
|
|
297
|
-
|
|
298
|
-
- Add to `Info.plist`: `GIDClientID`, `GIDServerClientID` (optional), `MSALClientID`, `MSALTenant` (optional), `MSALB2cDomain` (optional).
|
|
299
|
-
- Add URL schemes in `Info.plist`:
|
|
300
|
-
- Google: `com.googleusercontent.apps.<YOUR_IOS_CLIENT_ID>`
|
|
301
|
-
- Microsoft: `msauth.<your.bundle.id>` (used for `msauth.<bundle.id>://auth`)
|
|
302
|
-
- Enable the “Sign in with Apple” capability if you use Apple Sign-In.
|
|
303
|
-
|
|
304
|
-
**Android**
|
|
305
|
-
|
|
306
|
-
- Add string resources in `res/values/strings.xml`:
|
|
307
|
-
- `nitro_auth_google_client_id` (Web client ID)
|
|
308
|
-
- `nitro_auth_microsoft_client_id`
|
|
309
|
-
- `nitro_auth_microsoft_tenant` (optional)
|
|
310
|
-
- `nitro_auth_microsoft_b2c_domain` (optional)
|
|
311
|
-
- `MicrosoftAuthActivity` is **automatically declared** by the library manifest — no manual `AndroidManifest.xml` entry is required for basic Microsoft OAuth redirect handling. If you need to customize the intent-filter (e.g., restrict the host/path to your specific package and client ID), you can override it in your app manifest:
|
|
312
|
-
|
|
313
|
-
```xml
|
|
314
|
-
<activity
|
|
315
|
-
android:name="com.auth.MicrosoftAuthActivity"
|
|
316
|
-
android:exported="true"
|
|
317
|
-
android:launchMode="singleTask">
|
|
318
|
-
<intent-filter>
|
|
319
|
-
<action android:name="android.intent.action.VIEW" />
|
|
320
|
-
<category android:name="android.intent.category.DEFAULT" />
|
|
321
|
-
<category android:name="android.intent.category.BROWSABLE" />
|
|
322
|
-
<data
|
|
323
|
-
android:scheme="msauth"
|
|
324
|
-
android:host="${applicationId}"
|
|
325
|
-
android:path="/YOUR_MICROSOFT_CLIENT_ID" />
|
|
326
|
-
</intent-filter>
|
|
327
|
-
</activity>
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
### Web Setup
|
|
331
|
-
|
|
332
|
-
Nitro Auth reads web configuration from `expo.extra`:
|
|
333
|
-
|
|
334
|
-
```json
|
|
335
|
-
{
|
|
336
|
-
"expo": {
|
|
337
|
-
"extra": {
|
|
338
|
-
"googleWebClientId": "YOUR_WEB_CLIENT_ID.apps.googleusercontent.com",
|
|
339
|
-
"microsoftClientId": "YOUR_AZURE_AD_CLIENT_ID",
|
|
340
|
-
"microsoftTenant": "common",
|
|
341
|
-
"microsoftB2cDomain": "your-tenant.b2clogin.com",
|
|
342
|
-
"appleWebClientId": "com.example.web",
|
|
343
|
-
"nitroAuthWebStorage": "session",
|
|
344
|
-
"nitroAuthPersistTokensOnWeb": false
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
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.
|
|
351
|
-
|
|
352
|
-
- `nitroAuthWebStorage`: `"session"` (default), `"local"`, or `"memory"`.
|
|
353
|
-
- `nitroAuthPersistTokensOnWeb`: `false` by default (recommended). Set `true` only if you need cross-reload token persistence.
|
|
104
|
+
### Plugin Options
|
|
354
105
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
<Image source={{ uri: user.photo }} />
|
|
369
|
-
<Text>{user.name}</Text>
|
|
370
|
-
<Button title="Sign Out" onPress={logout} />
|
|
371
|
-
</View>
|
|
372
|
-
);
|
|
373
|
-
}
|
|
106
|
+
| Option | Platform | Purpose |
|
|
107
|
+
| ---------------------------- | -------- | ---------------------------------------------------------------------- |
|
|
108
|
+
| `ios.googleClientId` | iOS | Google iOS OAuth client ID |
|
|
109
|
+
| `ios.googleServerClientId` | iOS | Google web/server client ID for server auth code flows |
|
|
110
|
+
| `ios.googleUrlScheme` | iOS | Reversed iOS client ID URL scheme |
|
|
111
|
+
| `ios.appleSignIn` | iOS | Adds Apple Sign-In entitlement when `true` |
|
|
112
|
+
| `ios.microsoftClientId` | iOS | Microsoft app/client ID |
|
|
113
|
+
| `ios.microsoftTenant` | iOS | Microsoft tenant, `common`, `organizations`, `consumers`, or tenant ID |
|
|
114
|
+
| `ios.microsoftB2cDomain` | iOS | Azure AD B2C domain |
|
|
115
|
+
| `android.googleClientId` | Android | Google web OAuth client ID |
|
|
116
|
+
| `android.microsoftClientId` | Android | Microsoft app/client ID |
|
|
117
|
+
| `android.microsoftTenant` | Android | Microsoft tenant |
|
|
118
|
+
| `android.microsoftB2cDomain` | Android | Azure AD B2C domain |
|
|
374
119
|
|
|
375
|
-
|
|
376
|
-
<View>
|
|
377
|
-
{error && <Text style={{ color: "red" }}>{error.message}</Text>}
|
|
378
|
-
{!hasPlayServices && <Text>Please install Google Play Services</Text>}
|
|
120
|
+
## Provider Setup
|
|
379
121
|
|
|
380
|
-
|
|
381
|
-
provider="google"
|
|
382
|
-
onPress={() => login("google")}
|
|
383
|
-
disabled={loading || !hasPlayServices}
|
|
384
|
-
/>
|
|
385
|
-
<SocialButton
|
|
386
|
-
provider="apple"
|
|
387
|
-
onPress={() => login("apple")}
|
|
388
|
-
disabled={loading}
|
|
389
|
-
/>
|
|
390
|
-
<SocialButton
|
|
391
|
-
provider="microsoft"
|
|
392
|
-
onPress={() => login("microsoft")}
|
|
393
|
-
disabled={loading}
|
|
394
|
-
/>
|
|
395
|
-
</View>
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
```
|
|
122
|
+
### Google Sign-In
|
|
399
123
|
|
|
400
|
-
|
|
124
|
+
Create OAuth clients in Google Cloud Console:
|
|
401
125
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
tenant: "your-tenant-id",
|
|
406
|
-
prompt: "select_account", // 'login' | 'consent' | 'select_account' | 'none'
|
|
407
|
-
scopes: ["openid", "email", "profile", "User.Read"],
|
|
408
|
-
loginHint: "user@example.com",
|
|
409
|
-
});
|
|
410
|
-
```
|
|
126
|
+
- iOS client ID for your bundle identifier.
|
|
127
|
+
- Web client ID for Android, web, and server auth code flows.
|
|
128
|
+
- Android SHA-1/SHA-256 entries for local debug and release signing.
|
|
411
129
|
|
|
412
|
-
|
|
130
|
+
Use the iOS reversed client ID as `GOOGLE_IOS_URL_SCHEME`.
|
|
413
131
|
|
|
414
|
-
|
|
415
|
-
await login("microsoft", {
|
|
416
|
-
tenant: "your-tenant.onmicrosoft.com/B2C_1_signin",
|
|
417
|
-
scopes: ["openid", "email", "profile", "offline_access"],
|
|
418
|
-
});
|
|
419
|
-
```
|
|
132
|
+
### Apple Sign-In
|
|
420
133
|
|
|
421
|
-
|
|
134
|
+
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.
|
|
422
135
|
|
|
423
|
-
|
|
136
|
+
Apple Sign-In is supported on iOS and web. It is intentionally reported as `unsupported_provider` on Android.
|
|
424
137
|
|
|
425
|
-
###
|
|
138
|
+
### Microsoft Entra ID
|
|
426
139
|
|
|
427
|
-
|
|
428
|
-
bun remove @react-native-google-signin/google-signin
|
|
429
|
-
bun add react-native-nitro-auth react-native-nitro-modules
|
|
430
|
-
```
|
|
140
|
+
Create an app registration in Microsoft Entra ID and add redirect URIs:
|
|
431
141
|
|
|
432
|
-
|
|
142
|
+
- iOS: `msauth.<bundleIdentifier>://auth`
|
|
143
|
+
- Android: `msauth://<androidPackage>/<clientId>`
|
|
144
|
+
- Web: your web origin, for example `https://app.example.com`
|
|
433
145
|
|
|
434
|
-
|
|
146
|
+
Use `microsoftTenant` for `common`, `organizations`, `consumers`, a tenant ID, or a B2C policy path. Use `microsoftB2cDomain` for Azure AD B2C.
|
|
435
147
|
|
|
436
|
-
|
|
148
|
+
## Quick Start
|
|
437
149
|
|
|
438
|
-
```
|
|
439
|
-
{
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
]
|
|
454
|
-
],
|
|
455
|
-
"extra": {
|
|
456
|
-
"googleWebClientId": "YOUR_WEB_CLIENT_ID.apps.googleusercontent.com"
|
|
150
|
+
```tsx
|
|
151
|
+
import { Button, Text, View } from "react-native";
|
|
152
|
+
import { AuthError, useAuth } from "react-native-nitro-auth";
|
|
153
|
+
|
|
154
|
+
export function SignInScreen() {
|
|
155
|
+
const { user, loading, login, logout, getAccessToken } = useAuth();
|
|
156
|
+
|
|
157
|
+
async function signInWithGoogle() {
|
|
158
|
+
try {
|
|
159
|
+
await login("google", {
|
|
160
|
+
scopes: ["email", "profile"],
|
|
161
|
+
});
|
|
162
|
+
} catch (e) {
|
|
163
|
+
const error = AuthError.from(e);
|
|
164
|
+
console.warn(error.code, error.underlyingMessage);
|
|
457
165
|
}
|
|
458
166
|
}
|
|
459
|
-
}
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
**Bare React Native:**
|
|
463
|
-
|
|
464
|
-
- iOS: add `GIDClientID` (and optionally `GIDServerClientID`) to `Info.plist` and set the URL scheme.
|
|
465
|
-
- Android: add `nitro_auth_google_client_id` string resource in `res/values/strings.xml` (use your Web Client ID).
|
|
466
|
-
|
|
467
|
-
### 3) Update API usage
|
|
468
|
-
|
|
469
|
-
| @react-native-google-signin/google-signin | Nitro Auth |
|
|
470
|
-
| ----------------------------------------- | --------------------------------------------------------- |
|
|
471
|
-
| `GoogleSignin.configure({...})` | Configure in plugin / native config |
|
|
472
|
-
| `GoogleSignin.signIn()` | `login("google")` or `<SocialButton provider="google" />` |
|
|
473
|
-
| `GoogleSignin.signOut()` | `logout()` |
|
|
474
|
-
| `GoogleSignin.getTokens()` | `getAccessToken()` or `refreshToken()` |
|
|
475
|
-
| `GoogleSignin.hasPlayServices()` | `hasPlayServices` from `useAuth()` |
|
|
476
|
-
|
|
477
|
-
**Example migration:**
|
|
478
|
-
|
|
479
|
-
```tsx
|
|
480
|
-
// Before
|
|
481
|
-
import { GoogleSignin } from "@react-native-google-signin/google-signin";
|
|
482
|
-
|
|
483
|
-
await GoogleSignin.signIn();
|
|
484
|
-
const tokens = await GoogleSignin.getTokens();
|
|
485
167
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
168
|
+
async function readToken() {
|
|
169
|
+
const token = await getAccessToken();
|
|
170
|
+
console.log(token);
|
|
171
|
+
}
|
|
490
172
|
|
|
491
|
-
|
|
492
|
-
|
|
173
|
+
return (
|
|
174
|
+
<View>
|
|
175
|
+
<Text>{user?.email ?? "Signed out"}</Text>
|
|
176
|
+
<Button
|
|
177
|
+
title={loading ? "Signing in..." : "Sign in with Google"}
|
|
178
|
+
onPress={signInWithGoogle}
|
|
179
|
+
/>
|
|
180
|
+
<Button title="Get access token" onPress={readToken} />
|
|
181
|
+
<Button title="Sign out" onPress={logout} />
|
|
182
|
+
</View>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
493
185
|
```
|
|
494
186
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
If you previously called `GoogleSignin.configure()` at app startup, remove it. Nitro Auth loads configuration from the plugin/native settings at runtime.
|
|
498
|
-
|
|
499
|
-
## Advanced Features
|
|
500
|
-
|
|
501
|
-
### Silent Restore
|
|
502
|
-
|
|
503
|
-
Attempts to restore provider SDK sessions on app startup.
|
|
504
|
-
|
|
505
|
-
- Google: restore is supported via provider SDK session state.
|
|
506
|
-
- Apple: provider credentials are re-requested by OS flow.
|
|
507
|
-
- Microsoft: no internal persistence; restore requires your app/backend session strategy.
|
|
187
|
+
## SocialButton
|
|
508
188
|
|
|
509
189
|
```tsx
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
190
|
+
import { SocialButton } from "react-native-nitro-auth";
|
|
191
|
+
|
|
192
|
+
export function AuthButtons() {
|
|
193
|
+
return (
|
|
194
|
+
<>
|
|
195
|
+
<SocialButton provider="google" />
|
|
196
|
+
<SocialButton provider="apple" variant="black" />
|
|
197
|
+
<SocialButton provider="microsoft" variant="outline" />
|
|
198
|
+
</>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
513
201
|
```
|
|
514
202
|
|
|
515
|
-
|
|
203
|
+
## AuthService
|
|
516
204
|
|
|
517
|
-
|
|
205
|
+
Use `AuthService` when you need auth outside React components.
|
|
518
206
|
|
|
519
207
|
```ts
|
|
520
208
|
import { AuthService } from "react-native-nitro-auth";
|
|
521
209
|
|
|
210
|
+
await AuthService.silentRestore();
|
|
211
|
+
|
|
522
212
|
const unsubscribe = AuthService.onAuthStateChanged((user) => {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
213
|
+
console.log(user?.email);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const tokensUnsubscribe = AuthService.onTokensRefreshed((tokens) => {
|
|
217
|
+
console.log(tokens.expirationTime);
|
|
528
218
|
});
|
|
529
219
|
|
|
530
|
-
// Later...
|
|
531
220
|
unsubscribe();
|
|
221
|
+
tokensUnsubscribe();
|
|
532
222
|
```
|
|
533
223
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
Be notified whenever tokens are refreshed automatically (or manually):
|
|
224
|
+
## Login Options
|
|
537
225
|
|
|
538
226
|
```ts
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
227
|
+
await login("google", {
|
|
228
|
+
scopes: ["email", "profile"],
|
|
229
|
+
loginHint: "user@example.com",
|
|
230
|
+
useOneTap: true,
|
|
231
|
+
useSheet: true,
|
|
232
|
+
forceAccountPicker: true,
|
|
233
|
+
useLegacyGoogleSignIn: true,
|
|
544
234
|
});
|
|
545
|
-
```
|
|
546
235
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
const { requestScopes, revokeScopes, scopes } = useAuth();
|
|
553
|
-
|
|
554
|
-
const handleCalendar = async () => {
|
|
555
|
-
try {
|
|
556
|
-
await requestScopes(["https://www.googleapis.com/auth/calendar.readonly"]);
|
|
557
|
-
console.log("Got calendar access!");
|
|
558
|
-
} catch (e) {
|
|
559
|
-
console.error("Scope request failed");
|
|
560
|
-
}
|
|
561
|
-
};
|
|
236
|
+
await login("microsoft", {
|
|
237
|
+
scopes: ["openid", "profile", "email", "offline_access", "User.Read"],
|
|
238
|
+
tenant: "organizations",
|
|
239
|
+
prompt: "select_account",
|
|
240
|
+
});
|
|
562
241
|
```
|
|
563
242
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
243
|
+
| Option | Applies to | Notes |
|
|
244
|
+
| ----------------------- | ----------------- | ---------------------------------------------------- |
|
|
245
|
+
| `scopes` | Google, Microsoft | Requested OAuth scopes |
|
|
246
|
+
| `loginHint` | Google, Microsoft | Prefills account selection when supported |
|
|
247
|
+
| `useOneTap` | Android Google | Enables Credential Manager auto-select |
|
|
248
|
+
| `useSheet` | iOS Google | Uses native sign-in sheet behavior |
|
|
249
|
+
| `forceAccountPicker` | Google | Forces account picker |
|
|
250
|
+
| `useLegacyGoogleSignIn` | Android Google | Uses legacy Google Sign-In path for server auth code |
|
|
251
|
+
| `tenant` | Microsoft | Overrides configured tenant |
|
|
252
|
+
| `prompt` | Microsoft | `login`, `consent`, `select_account`, or `none` |
|
|
567
253
|
|
|
568
|
-
|
|
254
|
+
## Incremental Scopes
|
|
569
255
|
|
|
570
256
|
```ts
|
|
571
|
-
|
|
572
|
-
import { createStorageItem, StorageScope } from "react-native-nitro-storage";
|
|
573
|
-
|
|
574
|
-
type AuthSnapshot = {
|
|
575
|
-
user: AuthUser | undefined;
|
|
576
|
-
scopes: string[];
|
|
577
|
-
updatedAt: number | undefined;
|
|
578
|
-
};
|
|
579
|
-
|
|
580
|
-
const authSnapshotItem = createStorageItem<AuthSnapshot>({
|
|
581
|
-
key: "auth_snapshot",
|
|
582
|
-
scope: StorageScope.Disk,
|
|
583
|
-
defaultValue: {
|
|
584
|
-
user: undefined,
|
|
585
|
-
scopes: [],
|
|
586
|
-
updatedAt: undefined,
|
|
587
|
-
},
|
|
588
|
-
});
|
|
257
|
+
const calendarScope = "https://www.googleapis.com/auth/calendar.readonly";
|
|
589
258
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
if (!user) return;
|
|
593
|
-
|
|
594
|
-
authSnapshotItem.set({
|
|
595
|
-
user,
|
|
596
|
-
scopes: AuthService.grantedScopes,
|
|
597
|
-
updatedAt: Date.now(),
|
|
598
|
-
});
|
|
599
|
-
});
|
|
600
|
-
|
|
601
|
-
// Keep token/expiration fields fresh in persisted snapshot
|
|
602
|
-
AuthService.onTokensRefreshed((tokens) => {
|
|
603
|
-
authSnapshotItem.set((prev) => {
|
|
604
|
-
if (!prev.user) return prev;
|
|
605
|
-
|
|
606
|
-
return {
|
|
607
|
-
...prev,
|
|
608
|
-
user: {
|
|
609
|
-
...prev.user,
|
|
610
|
-
accessToken: tokens.accessToken ?? prev.user.accessToken,
|
|
611
|
-
idToken: tokens.idToken ?? prev.user.idToken,
|
|
612
|
-
refreshToken: tokens.refreshToken ?? prev.user.refreshToken,
|
|
613
|
-
expirationTime: tokens.expirationTime ?? prev.user.expirationTime,
|
|
614
|
-
},
|
|
615
|
-
updatedAt: Date.now(),
|
|
616
|
-
};
|
|
617
|
-
});
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
// Clear on logout
|
|
621
|
-
function logout() {
|
|
622
|
-
AuthService.logout();
|
|
623
|
-
authSnapshotItem.set({
|
|
624
|
-
user: undefined,
|
|
625
|
-
scopes: [],
|
|
626
|
-
updatedAt: undefined,
|
|
627
|
-
});
|
|
628
|
-
}
|
|
259
|
+
await requestScopes([calendarScope]);
|
|
260
|
+
await revokeScopes([calendarScope]);
|
|
629
261
|
```
|
|
630
262
|
|
|
631
|
-
|
|
263
|
+
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.
|
|
632
264
|
|
|
633
|
-
|
|
265
|
+
## Storage Model
|
|
634
266
|
|
|
635
|
-
|
|
636
|
-
- **Apple Sign-In**: iOS + web only.
|
|
637
|
-
- **Microsoft (Azure AD / B2C)**: iOS, Android, and web with PKCE/state/nonce protections.
|
|
267
|
+
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.
|
|
638
268
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
1. Configure client IDs, URL schemes, and redirect URIs per platform/provider.
|
|
642
|
-
2. Call `silentRestore()` during app startup to rehydrate provider session state when available.
|
|
643
|
-
3. Persist only app-owned snapshots/tokens (for example with `react-native-nitro-storage`), then clear them on logout.
|
|
644
|
-
4. On Android Google, use `useLegacyGoogleSignIn: true` when backend flows require `serverAuthCode`.
|
|
645
|
-
5. Treat token fields as optional and branch by provider/flow.
|
|
646
|
-
6. Keep web sensitive tokens memory-only unless you explicitly require persistent web tokens (`nitroAuthPersistTokensOnWeb: true`).
|
|
647
|
-
7. Enable logging only in development, and monitor normalized error codes in production.
|
|
648
|
-
|
|
649
|
-
### Logging & Debugging
|
|
650
|
-
|
|
651
|
-
Enable verbose logging to see detailed OAuth flow information in the console:
|
|
269
|
+
For app-managed persistence, store only the minimum state your product needs:
|
|
652
270
|
|
|
653
271
|
```ts
|
|
654
272
|
import { AuthService } from "react-native-nitro-auth";
|
|
655
273
|
|
|
656
|
-
|
|
274
|
+
const snapshot = {
|
|
275
|
+
user: AuthService.currentUser,
|
|
276
|
+
scopes: AuthService.grantedScopes,
|
|
277
|
+
updatedAt: Date.now(),
|
|
278
|
+
};
|
|
657
279
|
```
|
|
658
280
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
Nitro Auth provides synchronous access to in-memory state, while token retrieval remains async:
|
|
662
|
-
|
|
663
|
-
```ts
|
|
664
|
-
// Quick access to what we have in memory
|
|
665
|
-
const user = AuthService.currentUser;
|
|
666
|
-
const scopes = AuthService.grantedScopes;
|
|
281
|
+
On web, the default is also memory storage. You can opt into browser storage with:
|
|
667
282
|
|
|
668
|
-
|
|
669
|
-
|
|
283
|
+
```js
|
|
284
|
+
extra: {
|
|
285
|
+
nitroAuthWebStorage: "session", // "session", "local", or "memory"
|
|
286
|
+
nitroAuthPersistTokensOnWeb: true,
|
|
287
|
+
}
|
|
670
288
|
```
|
|
671
289
|
|
|
672
|
-
|
|
290
|
+
## Error Contract
|
|
673
291
|
|
|
674
|
-
All
|
|
292
|
+
All public async APIs throw `AuthError`, including provider errors surfaced by native and web `AuthService` implementations.
|
|
675
293
|
|
|
676
294
|
```ts
|
|
677
|
-
import { AuthError } from "react-native-nitro-auth";
|
|
678
|
-
|
|
679
295
|
try {
|
|
680
|
-
await login("
|
|
296
|
+
await AuthService.login("microsoft");
|
|
681
297
|
} catch (e) {
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
}
|
|
298
|
+
const error = AuthError.from(e);
|
|
299
|
+
switch (error.code) {
|
|
300
|
+
case "cancelled":
|
|
301
|
+
break;
|
|
302
|
+
case "configuration_error":
|
|
303
|
+
break;
|
|
304
|
+
case "token_error":
|
|
305
|
+
break;
|
|
306
|
+
default:
|
|
307
|
+
break;
|
|
693
308
|
}
|
|
694
309
|
}
|
|
695
310
|
```
|
|
696
311
|
|
|
697
|
-
|
|
698
|
-
| ---------------------- | --------------------------------------------------------------- |
|
|
699
|
-
| `cancelled` | The user cancelled the sign-in flow or dismissed the popup |
|
|
700
|
-
| `timeout` | The login popup/flow timed out |
|
|
701
|
-
| `popup_blocked` | The browser blocked the popup window |
|
|
702
|
-
| `network_error` | A network or connectivity error occurred |
|
|
703
|
-
| `configuration_error` | Missing client IDs, invalid tenant, or misconfigured setup |
|
|
704
|
-
| `not_signed_in` | The operation requires an authenticated user/session |
|
|
705
|
-
| `operation_in_progress`| Another auth flow of the same kind is already running |
|
|
706
|
-
| `unsupported_provider` | The provider is not supported on this platform |
|
|
707
|
-
| `invalid_state` | PKCE state mismatch — possible CSRF attack |
|
|
708
|
-
| `invalid_nonce` | Nonce mismatch in token response — possible replay attack |
|
|
709
|
-
| `token_error` | Token exchange or storage failed |
|
|
710
|
-
| `no_id_token` | No `id_token` in token response |
|
|
711
|
-
| `parse_error` | Failed to parse token response |
|
|
712
|
-
| `refresh_failed` | Refresh token flow failed (token may be expired or revoked) |
|
|
713
|
-
| `unknown` | An unknown or unmapped error occurred |
|
|
714
|
-
|
|
715
|
-
### Native Error Metadata
|
|
716
|
-
|
|
717
|
-
`AuthError` carries the raw provider/native message in `underlyingMessage` when the platform error didn't map to a known code:
|
|
312
|
+
Known error codes:
|
|
718
313
|
|
|
719
314
|
```ts
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
315
|
+
type AuthErrorCode =
|
|
316
|
+
| "cancelled"
|
|
317
|
+
| "timeout"
|
|
318
|
+
| "popup_blocked"
|
|
319
|
+
| "network_error"
|
|
320
|
+
| "configuration_error"
|
|
321
|
+
| "not_signed_in"
|
|
322
|
+
| "operation_in_progress"
|
|
323
|
+
| "unsupported_provider"
|
|
324
|
+
| "invalid_state"
|
|
325
|
+
| "invalid_nonce"
|
|
326
|
+
| "token_error"
|
|
327
|
+
| "no_id_token"
|
|
328
|
+
| "parse_error"
|
|
329
|
+
| "refresh_failed"
|
|
330
|
+
| "unknown";
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
`underlyingMessage` keeps the raw native or OAuth message when it differs from the stable code.
|
|
736
334
|
|
|
737
|
-
|
|
738
|
-
- `invalid_state` or `invalid_nonce`: ensure the redirect URI in your provider console matches your app config exactly. These indicate a potential CSRF or replay attack — do not retry silently.
|
|
739
|
-
- `refresh_failed`: the refresh token is likely expired or revoked. Clear the session and prompt the user to sign in again. On Android and web, structured error details from the provider (e.g. `invalid_grant`) are surfaced via `error.underlyingMessage`.
|
|
740
|
-
- `hasPlayServices` is false: prompt the user to install/update Google Play Services or disable One-Tap.
|
|
741
|
-
- Apple web login fails: confirm `appleWebClientId` is set and your domain is registered with Apple.
|
|
742
|
-
- Microsoft Android redirect hangs: confirm the `msauth://` redirect URI in your Azure app matches your package name and client ID.
|
|
743
|
-
|
|
744
|
-
### Automatic Token Refresh
|
|
335
|
+
## API Reference
|
|
745
336
|
|
|
746
|
-
|
|
337
|
+
### Exports
|
|
747
338
|
|
|
748
339
|
```ts
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
// This will silently refresh if needed!
|
|
752
|
-
const token = await getAccessToken();
|
|
340
|
+
export * from "react-native-nitro-auth";
|
|
753
341
|
```
|
|
754
342
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
If you need to access Google APIs from your backend (e.g., Google Calendar integration), you can use the `serverAuthCode`. This code is returned during login and can be exchanged for tokens on your server:
|
|
758
|
-
|
|
759
|
-
```ts
|
|
760
|
-
const { user } = useAuth();
|
|
761
|
-
|
|
762
|
-
if (user?.serverAuthCode) {
|
|
763
|
-
// Send this to your backend!
|
|
764
|
-
await api.verifyGoogleAccess(user.serverAuthCode);
|
|
765
|
-
}
|
|
766
|
-
```
|
|
343
|
+
Main exports:
|
|
767
344
|
|
|
768
|
-
|
|
345
|
+
- `useAuth()`
|
|
346
|
+
- `AuthService`
|
|
347
|
+
- `SocialButton`
|
|
348
|
+
- `AuthError`
|
|
349
|
+
- `isAuthErrorCode()`
|
|
350
|
+
- `toAuthErrorCode()`
|
|
351
|
+
- `AuthProvider`
|
|
352
|
+
- `AuthUser`
|
|
353
|
+
- `AuthTokens`
|
|
354
|
+
- `LoginOptions`
|
|
769
355
|
|
|
770
|
-
|
|
356
|
+
### useAuth()
|
|
771
357
|
|
|
772
358
|
```ts
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
359
|
+
type UseAuthReturn = {
|
|
360
|
+
user: AuthUser | undefined;
|
|
361
|
+
scopes: string[];
|
|
362
|
+
loading: boolean;
|
|
363
|
+
error: AuthError | undefined;
|
|
364
|
+
hasPlayServices: boolean;
|
|
365
|
+
login(provider: AuthProvider, options?: LoginOptions): Promise<void>;
|
|
366
|
+
logout(): void;
|
|
367
|
+
requestScopes(scopes: string[]): Promise<void>;
|
|
368
|
+
revokeScopes(scopes: string[]): Promise<void>;
|
|
369
|
+
getAccessToken(): Promise<string | undefined>;
|
|
370
|
+
refreshToken(): Promise<AuthTokens>;
|
|
371
|
+
silentRestore(): Promise<void>;
|
|
372
|
+
};
|
|
777
373
|
```
|
|
778
374
|
|
|
779
|
-
|
|
780
|
-
> One-Tap requires Google Play Services. You can check `hasPlayServices` from `useAuth()` and show a fallback UI if needed.
|
|
781
|
-
|
|
782
|
-
### Android Legacy Google Sign-In (Server Auth Code)
|
|
783
|
-
|
|
784
|
-
Credential Manager is the recommended default on Android, but it **does not return** `serverAuthCode`.
|
|
785
|
-
If your backend requires `serverAuthCode`, opt into the legacy flow:
|
|
375
|
+
### AuthUser
|
|
786
376
|
|
|
787
377
|
```ts
|
|
788
|
-
|
|
378
|
+
type AuthUser = {
|
|
379
|
+
provider: "google" | "apple" | "microsoft";
|
|
380
|
+
email?: string;
|
|
381
|
+
name?: string;
|
|
382
|
+
photo?: string;
|
|
383
|
+
idToken?: string;
|
|
384
|
+
accessToken?: string;
|
|
385
|
+
refreshToken?: string;
|
|
386
|
+
serverAuthCode?: string;
|
|
387
|
+
scopes?: string[];
|
|
388
|
+
expirationTime?: number;
|
|
389
|
+
underlyingError?: string;
|
|
390
|
+
};
|
|
789
391
|
```
|
|
790
392
|
|
|
791
|
-
|
|
393
|
+
## Example App
|
|
792
394
|
|
|
793
|
-
|
|
395
|
+
The example app is the fastest way to verify setup and read a complete integration.
|
|
794
396
|
|
|
795
|
-
```
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
397
|
+
```sh
|
|
398
|
+
cp apps/example/.env.example apps/example/.env.local
|
|
399
|
+
bun install
|
|
400
|
+
bun example:prebuild:clean
|
|
401
|
+
bun example:ios
|
|
402
|
+
bun example:android
|
|
800
403
|
```
|
|
801
404
|
|
|
802
|
-
|
|
405
|
+
The demo includes:
|
|
803
406
|
|
|
804
|
-
-
|
|
805
|
-
-
|
|
806
|
-
-
|
|
407
|
+
- Provider cards for Google, Apple, and Microsoft.
|
|
408
|
+
- Token and scope operations.
|
|
409
|
+
- Silent restore and account picker actions.
|
|
410
|
+
- App-owned disk snapshot example with `react-native-nitro-storage`.
|
|
411
|
+
- Runtime smoke tests for the public API.
|
|
807
412
|
|
|
808
|
-
|
|
413
|
+
## Troubleshooting
|
|
809
414
|
|
|
810
|
-
|
|
415
|
+
| Symptom | Check |
|
|
416
|
+
| ------------------------------------- | -------------------------------------------------------------------------------- |
|
|
417
|
+
| `configuration_error` on Google | Client ID is missing or wrong for the current platform |
|
|
418
|
+
| Google works in debug but not release | Add release SHA-1/SHA-256 fingerprints to Google Cloud Console |
|
|
419
|
+
| Android `hasPlayServices` is false | Use an emulator image with Google Play Services |
|
|
420
|
+
| Apple email/name missing | Apple only returns these fields on first authorization |
|
|
421
|
+
| Microsoft `invalid_state` | Redirect URI or app resume path is wrong, or an old auth redirect completed late |
|
|
422
|
+
| Microsoft `token_error` | Check tenant, client ID, redirect URI, and requested scopes |
|
|
423
|
+
| Web popup blocked | Call `login()` from a user gesture such as a button press |
|
|
424
|
+
| `operation_in_progress` | A provider flow is already active; wait for it to finish or sign out |
|
|
811
425
|
|
|
812
|
-
|
|
426
|
+
## Production Notes
|
|
813
427
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
toAuthErrorCode,
|
|
820
|
-
SocialButton,
|
|
821
|
-
useAuth,
|
|
822
|
-
type UseAuthReturn,
|
|
823
|
-
type Auth,
|
|
824
|
-
type AuthUser,
|
|
825
|
-
type AuthTokens,
|
|
826
|
-
type AuthProvider,
|
|
827
|
-
type AuthErrorCode,
|
|
828
|
-
type LoginOptions,
|
|
829
|
-
} from "react-native-nitro-auth";
|
|
830
|
-
```
|
|
428
|
+
- Verify ID tokens on your backend. Client-side JWT parsing is for display and expiration hints only.
|
|
429
|
+
- Store refresh tokens only in storage your app explicitly owns and secures.
|
|
430
|
+
- Keep Google debug and release signing fingerprints in sync with your OAuth clients.
|
|
431
|
+
- Add provider-specific redirect URIs for every environment.
|
|
432
|
+
- Run the example app on iOS and Android before shipping provider config changes.
|
|
831
433
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
| Type | Definition |
|
|
835
|
-
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
836
|
-
| `AuthProvider` | `"google" \| "apple" \| "microsoft"` |
|
|
837
|
-
| `AuthErrorCode` | `"cancelled" \| "timeout" \| "popup_blocked" \| "network_error" \| "configuration_error" \| "not_signed_in" \| "operation_in_progress" \| "unsupported_provider" \| "invalid_state" \| "invalid_nonce" \| "token_error" \| "no_id_token" \| "parse_error" \| "refresh_failed" \| "unknown"` |
|
|
838
|
-
| `MicrosoftPrompt` | `"login" \| "consent" \| "select_account" \| "none"` |
|
|
839
|
-
|
|
840
|
-
### `AuthUser`
|
|
841
|
-
|
|
842
|
-
| Field | Type | Description |
|
|
843
|
-
| ----------------- | ----------------------- | -------------------------------------------------------------------------- |
|
|
844
|
-
| `provider` | `AuthProvider` | Provider that authenticated the user |
|
|
845
|
-
| `email` | `string \| undefined` | User email |
|
|
846
|
-
| `name` | `string \| undefined` | Display name |
|
|
847
|
-
| `photo` | `string \| undefined` | Profile image URL (Google) |
|
|
848
|
-
| `idToken` | `string \| undefined` | OIDC ID token |
|
|
849
|
-
| `accessToken` | `string \| undefined` | OAuth access token |
|
|
850
|
-
| `refreshToken` | `string \| undefined` | OAuth refresh token |
|
|
851
|
-
| `serverAuthCode` | `string \| undefined` | Google server auth code (legacy Android flow + backend exchange scenarios) |
|
|
852
|
-
| `scopes` | `string[] \| undefined` | Granted scopes for current session |
|
|
853
|
-
| `expirationTime` | `number \| undefined` | Expiration timestamp in milliseconds since epoch |
|
|
854
|
-
| `underlyingError` | `string \| undefined` | Raw provider/native error message |
|
|
855
|
-
|
|
856
|
-
> [!NOTE]
|
|
857
|
-
> 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.
|
|
858
|
-
|
|
859
|
-
### `AuthTokens`
|
|
860
|
-
|
|
861
|
-
| Field | Type | Description |
|
|
862
|
-
| ---------------- | --------------------- | ----------------------------- |
|
|
863
|
-
| `accessToken` | `string \| undefined` | Refreshed access token |
|
|
864
|
-
| `idToken` | `string \| undefined` | Refreshed ID token |
|
|
865
|
-
| `refreshToken` | `string \| undefined` | Refresh token (if available) |
|
|
866
|
-
| `expirationTime` | `number \| undefined` | Optional expiration timestamp |
|
|
867
|
-
|
|
868
|
-
### `LoginOptions`
|
|
869
|
-
|
|
870
|
-
| Option | Type | Platform | Description |
|
|
871
|
-
| ----------------------- | ----------------- | --------- | --------------------------------------------------------------------------------- |
|
|
872
|
-
| `scopes` | `string[]` | All | Requested scopes (defaults are provider-specific) |
|
|
873
|
-
| `loginHint` | `string` | All | Prefills account identifier |
|
|
874
|
-
| `useOneTap` | `boolean` | Android | Use Credential Manager/One-Tap flow |
|
|
875
|
-
| `useSheet` | `boolean` | iOS | Use native Google Sign-In sheet |
|
|
876
|
-
| `forceAccountPicker` | `boolean` | All | Always show account chooser; Android Google uses the legacy chooser path |
|
|
877
|
-
| `useLegacyGoogleSignIn` | `boolean` | Android | Use legacy Google Sign-In (required when you need `serverAuthCode`) |
|
|
878
|
-
| `tenant` | `string` | Microsoft | Tenant (`common`, `organizations`, `consumers`, tenant id, or full authority URL) |
|
|
879
|
-
| `prompt` | `MicrosoftPrompt` | Microsoft | Prompt behavior |
|
|
880
|
-
|
|
881
|
-
### `useAuth()`
|
|
434
|
+
## Release Checks
|
|
882
435
|
|
|
883
|
-
```
|
|
884
|
-
|
|
436
|
+
```sh
|
|
437
|
+
bun run publish-package:dry-run
|
|
885
438
|
```
|
|
886
439
|
|
|
887
|
-
|
|
888
|
-
| ----------------- | ------------------------------------------------------------------- | ---------------------------------------------------- |
|
|
889
|
-
| `user` | `AuthUser \| undefined` | Current in-memory user |
|
|
890
|
-
| `scopes` | `string[]` | Current granted scopes |
|
|
891
|
-
| `loading` | `boolean` | `true` while an auth operation is in-flight |
|
|
892
|
-
| `error` | `AuthError \| undefined` | Last operation error (typed, safe to switch on `.code`) |
|
|
893
|
-
| `hasPlayServices` | `boolean` | Android Play Services availability |
|
|
894
|
-
| `login` | `(provider: AuthProvider, options?: LoginOptions) => Promise<void>` | Starts provider login |
|
|
895
|
-
| `logout` | `() => void` | Clears current session |
|
|
896
|
-
| `requestScopes` | `(scopes: string[]) => Promise<void>` | Requests additional scopes |
|
|
897
|
-
| `revokeScopes` | `(scopes: string[]) => Promise<void>` | Revokes scopes in current session |
|
|
898
|
-
| `getAccessToken` | `() => Promise<string \| undefined>` | Returns access token, auto-refreshing when supported |
|
|
899
|
-
| `refreshToken` | `() => Promise<AuthTokens>` | Explicit refresh |
|
|
900
|
-
| `silentRestore` | `() => Promise<void>` | Restores provider SDK session (if available) |
|
|
901
|
-
|
|
902
|
-
### `AuthService`
|
|
903
|
-
|
|
904
|
-
Synchronous state + async operations (useful outside React trees).
|
|
905
|
-
|
|
906
|
-
#### Readonly state
|
|
907
|
-
|
|
908
|
-
| Property | Type | Description |
|
|
909
|
-
| ----------------- | ----------------------- | ---------------------------------- |
|
|
910
|
-
| `name` | `string` | Hybrid object name (`"Auth"`) |
|
|
911
|
-
| `currentUser` | `AuthUser \| undefined` | Current user snapshot |
|
|
912
|
-
| `grantedScopes` | `string[]` | Current scope snapshot |
|
|
913
|
-
| `hasPlayServices` | `boolean` | Android Play Services availability |
|
|
914
|
-
|
|
915
|
-
#### Methods
|
|
916
|
-
|
|
917
|
-
| Method | Signature | Description |
|
|
918
|
-
| -------------------- | -------------------------------------------------------- | -------------------------------- |
|
|
919
|
-
| `login` | `(provider, options?) => Promise<void>` | Starts login |
|
|
920
|
-
| `logout` | `() => void` | Clears session |
|
|
921
|
-
| `requestScopes` | `(scopes) => Promise<void>` | Incremental auth |
|
|
922
|
-
| `revokeScopes` | `(scopes) => Promise<void>` | Scope revoke |
|
|
923
|
-
| `getAccessToken` | `() => Promise<string \| undefined>` | Access token getter with refresh |
|
|
924
|
-
| `refreshToken` | `() => Promise<AuthTokens>` | Explicit token refresh |
|
|
925
|
-
| `silentRestore` | `() => Promise<void>` | Restore provider SDK session |
|
|
926
|
-
| `onAuthStateChanged` | `(callback: (user?: AuthUser) => void) => () => void` | Auth change listener |
|
|
927
|
-
| `onTokensRefreshed` | `(callback: (tokens: AuthTokens) => void) => () => void` | Token refresh listener |
|
|
928
|
-
| `setLoggingEnabled` | `(enabled: boolean) => void` | Debug logging toggle |
|
|
929
|
-
| `dispose` | `() => void` | Disposes hybrid object |
|
|
930
|
-
| `equals` | `(other: unknown) => boolean` | Hybrid object identity check |
|
|
931
|
-
|
|
932
|
-
### Storage Contract
|
|
933
|
-
|
|
934
|
-
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).
|
|
935
|
-
There is no public `setStorageAdapter`/`setJSStorageAdapter` API in this package.
|
|
936
|
-
|
|
937
|
-
### `SocialButton`
|
|
938
|
-
|
|
939
|
-
| Prop | Type | Default | Description |
|
|
940
|
-
| -------------- | ---------------------------------------------- | ----------- | ------------------------------------------- |
|
|
941
|
-
| `provider` | `AuthProvider` | required | Provider |
|
|
942
|
-
| `variant` | `"primary" \| "outline" \| "white" \| "black"` | `"primary"` | Visual style |
|
|
943
|
-
| `borderRadius` | `number` | `8` | Border radius |
|
|
944
|
-
| `style` | `ViewStyle` | `undefined` | Container style override |
|
|
945
|
-
| `textStyle` | `TextStyle` | `undefined` | Text style override |
|
|
946
|
-
| `disabled` | `boolean` | `false` | Disabled state |
|
|
947
|
-
| `onPress` | `() => void` | `undefined` | Custom press handler (skips built-in login) |
|
|
948
|
-
| `onSuccess` | `(user: AuthUser) => void` | `undefined` | Called after successful default login |
|
|
949
|
-
| `onError` | `(error: unknown) => void` | `undefined` | Called when default login fails |
|
|
950
|
-
|
|
951
|
-
### Config Plugin API (`app.json` / `app.config.js`)
|
|
952
|
-
|
|
953
|
-
`plugins: [["react-native-nitro-auth", { ios: {...}, android: {...} }]]`
|
|
954
|
-
|
|
955
|
-
#### iOS plugin options
|
|
956
|
-
|
|
957
|
-
| Option | Type | Description |
|
|
958
|
-
| ---------------------- | --------- | -------------------------------------------- |
|
|
959
|
-
| `googleClientId` | `string` | Writes `GIDClientID` |
|
|
960
|
-
| `googleServerClientId` | `string` | Writes `GIDServerClientID` |
|
|
961
|
-
| `googleUrlScheme` | `string` | Adds Google URL scheme |
|
|
962
|
-
| `appleSignIn` | `boolean` | Enables Apple Sign-In entitlement |
|
|
963
|
-
| `microsoftClientId` | `string` | Writes `MSALClientID` + MSAL redirect scheme |
|
|
964
|
-
| `microsoftTenant` | `string` | Writes `MSALTenant` |
|
|
965
|
-
| `microsoftB2cDomain` | `string` | Writes `MSALB2cDomain` |
|
|
966
|
-
|
|
967
|
-
#### Android plugin options
|
|
968
|
-
|
|
969
|
-
| Option | Type | Description |
|
|
970
|
-
| -------------------- | -------- | ---------------------------------------------------------------- |
|
|
971
|
-
| `googleClientId` | `string` | Writes `nitro_auth_google_client_id` string |
|
|
972
|
-
| `microsoftClientId` | `string` | Writes `nitro_auth_microsoft_client_id` + redirect intent filter |
|
|
973
|
-
| `microsoftTenant` | `string` | Writes `nitro_auth_microsoft_tenant` |
|
|
974
|
-
| `microsoftB2cDomain` | `string` | Writes `nitro_auth_microsoft_b2c_domain` |
|
|
975
|
-
|
|
976
|
-
### Web runtime config (`expo.extra`)
|
|
977
|
-
|
|
978
|
-
| Key | Type | Default | Description |
|
|
979
|
-
| ----------------------------- | ---------------------------------- | ----------- | --------------------------------------------------------- |
|
|
980
|
-
| `googleWebClientId` | `string` | `undefined` | Google web OAuth client id |
|
|
981
|
-
| `microsoftClientId` | `string` | `undefined` | Microsoft app client id |
|
|
982
|
-
| `microsoftTenant` | `string` | `"common"` | Microsoft tenant/authority |
|
|
983
|
-
| `microsoftB2cDomain` | `string` | `undefined` | B2C domain when applicable |
|
|
984
|
-
| `appleWebClientId` | `string` | `undefined` | Apple Service ID |
|
|
985
|
-
| `nitroAuthWebStorage` | `"session" \| "local" \| "memory"` | `"session"` | Storage for non-sensitive web cache |
|
|
986
|
-
| `nitroAuthPersistTokensOnWeb` | `boolean` | `false` | Persist sensitive tokens on web storage instead of memory |
|
|
987
|
-
|
|
988
|
-
### `AuthError`
|
|
989
|
-
|
|
990
|
-
All thrown errors from `AuthService` and `useAuth` are `AuthError` instances.
|
|
440
|
+
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`.
|
|
991
441
|
|
|
992
|
-
|
|
993
|
-
class AuthError extends Error {
|
|
994
|
-
readonly code: AuthErrorCode; // Always a valid AuthErrorCode — safe to switch on
|
|
995
|
-
readonly underlyingMessage?: string; // Raw native/platform string when it differs from code
|
|
996
|
-
static from(e: unknown): AuthError; // Wraps any value; passes AuthError instances through
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
function isAuthErrorCode(value: string): value is AuthErrorCode;
|
|
1000
|
-
function toAuthErrorCode(raw: string): AuthErrorCode; // Returns "unknown" for unrecognized strings
|
|
1001
|
-
```
|
|
442
|
+
For faster local iteration before the full release dry run:
|
|
1002
443
|
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
| `network_error` | Network failure |
|
|
1009
|
-
| `configuration_error` | Missing/invalid provider configuration |
|
|
1010
|
-
| `not_signed_in` | Operation requires an active authenticated user |
|
|
1011
|
-
| `operation_in_progress`| Another auth flow is already running |
|
|
1012
|
-
| `unsupported_provider` | Provider not supported on this platform |
|
|
1013
|
-
| `invalid_state` | PKCE state mismatch (possible CSRF) |
|
|
1014
|
-
| `invalid_nonce` | Nonce mismatch in token response |
|
|
1015
|
-
| `token_error` | Token exchange failed |
|
|
1016
|
-
| `no_id_token` | No `id_token` in token response |
|
|
1017
|
-
| `parse_error` | Failed to parse token response |
|
|
1018
|
-
| `refresh_failed` | Refresh token flow failed |
|
|
1019
|
-
| `unknown` | Unrecognized error |
|
|
1020
|
-
|
|
1021
|
-
## Quality Gates
|
|
1022
|
-
|
|
1023
|
-
From monorepo root:
|
|
1024
|
-
|
|
1025
|
-
```bash
|
|
1026
|
-
bun run format:check
|
|
1027
|
-
bun run lint
|
|
1028
|
-
bun run typecheck
|
|
444
|
+
```sh
|
|
445
|
+
bun run check
|
|
446
|
+
bun run test:cpp
|
|
447
|
+
bun run --cwd packages/react-native-nitro-auth test:coverage -- --runInBand
|
|
448
|
+
bun run --cwd packages/react-native-nitro-auth test:cpp:coverage
|
|
1029
449
|
```
|
|
1030
450
|
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
```bash
|
|
1034
|
-
# apps/example
|
|
1035
|
-
bun run format
|
|
1036
|
-
bun run lint
|
|
1037
|
-
bun run typecheck
|
|
451
|
+
Before shipping provider or native config changes, also verify the example app:
|
|
1038
452
|
|
|
1039
|
-
|
|
1040
|
-
bun run
|
|
1041
|
-
bun run
|
|
1042
|
-
bun run
|
|
1043
|
-
bun run test
|
|
453
|
+
```sh
|
|
454
|
+
bun run example:prebuild
|
|
455
|
+
bun run example:android
|
|
456
|
+
bun run example:ios
|
|
1044
457
|
```
|
|
1045
458
|
|
|
1046
|
-
## Platform Support
|
|
1047
|
-
|
|
1048
|
-
| Feature | iOS | Android | Web |
|
|
1049
|
-
| -------------------------- | --- | ------- | --- |
|
|
1050
|
-
| Google Sign-In | ✅ | ✅ | ✅ |
|
|
1051
|
-
| Apple Sign-In | ✅ | ❌ | ✅ |
|
|
1052
|
-
| Microsoft Sign-In | ✅ | ✅ | ✅ |
|
|
1053
|
-
| Custom OAuth Scopes | ✅ | ✅ | ✅ |
|
|
1054
|
-
| Incremental Authorization | ✅ | ✅ | ✅ |
|
|
1055
|
-
| Token Refresh | ✅ | ✅ | ✅ |
|
|
1056
|
-
| Native Session Persistence | ❌ | ❌ | — |
|
|
1057
|
-
| Web Auth Snapshot Cache | — | — | ✅ |
|
|
1058
|
-
| App-Owned Persistence | ✅ | ✅ | ✅ |
|
|
1059
|
-
| Auto-Refresh | ✅ | ✅ | ✅ |
|
|
1060
|
-
| Native C++ Performance | ✅ | ✅ | — |
|
|
1061
|
-
|
|
1062
|
-
## Architecture
|
|
1063
|
-
|
|
1064
|
-
`react-native-nitro-auth` is built using [Nitro Modules](https://github.com/mrousavy/nitro). Unlike traditional React Native modules, Nitro uses JSI to provide:
|
|
1065
|
-
|
|
1066
|
-
- **Zero-bridge overhead**: Calls are made directly from JS to C++.
|
|
1067
|
-
- **Type safety**: TypeScript types are automatically kept in sync with native C++ and Swift/Kotlin code.
|
|
1068
|
-
- **Synchronous access**: Properties like `currentUser` are accessible synchronously without async overhead.
|
|
1069
|
-
|
|
1070
459
|
## License
|
|
1071
460
|
|
|
1072
461
|
MIT
|