react-native-nitro-auth 0.6.2 → 0.6.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/CHANGELOG.md +20 -62
- package/README.md +50 -11
- package/android/src/main/java/com/auth/AuthAdapter.kt +5 -5
- package/ios/AuthAdapter.swift +18 -12
- package/lib/commonjs/Auth.web.js +75 -63
- package/lib/commonjs/Auth.web.js.map +1 -1
- package/lib/commonjs/ui/social-button.js +39 -31
- package/lib/commonjs/ui/social-button.js.map +1 -1
- package/lib/module/Auth.web.js +75 -63
- package/lib/module/Auth.web.js.map +1 -1
- package/lib/module/ui/social-button.js +40 -31
- package/lib/module/ui/social-button.js.map +1 -1
- package/lib/typescript/commonjs/Auth.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/social-button.d.ts +1 -1
- package/lib/typescript/commonjs/ui/social-button.d.ts.map +1 -1
- package/lib/typescript/module/Auth.web.d.ts.map +1 -1
- package/lib/typescript/module/ui/social-button.d.ts +1 -1
- package/lib/typescript/module/ui/social-button.d.ts.map +1 -1
- package/package.json +19 -2
- package/src/Auth.web.ts +143 -67
- package/src/ui/social-button.tsx +46 -38
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.6.
|
|
3
|
+
## 0.6.4 - 2026-06-11
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Added a modern `exports` map with `react-native`, `browser`, `import`, and `require` conditions plus explicit `./app.plugin`, `./app.plugin.js`, and `./package.json` subpaths, so bundlers and Node resolve the package deterministically.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Strengthened the package TypeScript configuration (`exactOptionalPropertyTypes`, `noUncheckedIndexedAccess`, `noImplicitOverride`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, `useUnknownInCatchVariables`) so editor and tooling diagnostics catch more mistakes at compile time.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Encoded iOS Microsoft token request bodies as form data so authorization codes, redirect URIs, and refresh tokens containing reserved characters are posted correctly.
|
|
16
|
+
|
|
17
|
+
## 0.6.3 - 2026-06-10
|
|
4
18
|
|
|
5
19
|
### Fixed
|
|
6
20
|
|
|
@@ -8,26 +22,20 @@
|
|
|
8
22
|
|
|
9
23
|
### Changed
|
|
10
24
|
|
|
11
|
-
- Updated
|
|
25
|
+
- Updated README setup, provider examples, option tables, error codes, and typed API documentation to match the current package surface.
|
|
26
|
+
- Added stronger compile-time coverage for provider-specific login options used by `AuthService.login()` and `useAuth().login()`.
|
|
12
27
|
|
|
13
28
|
## 0.6.1 - 2026-05-21
|
|
14
29
|
|
|
15
30
|
### Changed
|
|
16
31
|
|
|
17
|
-
- Updated the package
|
|
32
|
+
- Updated the package baseline to Expo SDK 56, React Native 0.85.3, React 19.2.3, TypeScript 6.0.3, Nitro Modules 0.35.7, and nitrogen 0.35.7.
|
|
18
33
|
- Raised the iOS deployment target to 16.4 for SDK 56 compatibility.
|
|
19
|
-
- Added release preflight checks for Expo dependency validation, Expo Doctor, config introspection, package build, tests, C++ tests, and publish dry run.
|
|
20
|
-
- Simplified the example app by keeping provider-specific advanced options collapsed by default.
|
|
21
|
-
- Updated README badges, setup commands, release checks, and typed API examples to match the 0.6.1 package state.
|
|
22
34
|
- Added compile-time coverage for provider-specific login option types.
|
|
23
|
-
- Added CI setup and versioned tool detection for LLVM C++ coverage tools.
|
|
24
|
-
- Added a CI-safe release preflight mode that skips unauthenticated npm publish dry runs while keeping local publish dry runs intact.
|
|
25
35
|
|
|
26
36
|
### Fixed
|
|
27
37
|
|
|
28
38
|
- Retained the active iOS Apple Sign-In controller until completion to avoid premature native lifecycle cleanup.
|
|
29
|
-
- Removed the example app's import-time native logging side effect.
|
|
30
|
-
- Removed Turbo cache-output warnings from lint and typecheck tasks.
|
|
31
39
|
|
|
32
40
|
## 0.6.0 - 2026-05-14
|
|
33
41
|
|
|
@@ -37,7 +45,7 @@
|
|
|
37
45
|
- Added Apple nonce and authorization-code/user-id result support.
|
|
38
46
|
- Added Microsoft tenant and prompt option coverage across native and web flows.
|
|
39
47
|
- Added `revokeAccess()` to the native/web auth API and `useAuth()` hook.
|
|
40
|
-
- Added native logging hooks
|
|
48
|
+
- Added native logging hooks.
|
|
41
49
|
- Added provider-specific TypeScript option types for `AuthService.login()` and `useAuth().login()`.
|
|
42
50
|
|
|
43
51
|
### Changed
|
|
@@ -48,86 +56,36 @@
|
|
|
48
56
|
|
|
49
57
|
### Fixed
|
|
50
58
|
|
|
51
|
-
- Fixed Android Metro watcher noise from transient Bun `node_modules/.old-*` directories in the example app.
|
|
52
59
|
- Fixed Android Google cancellation handling so cancellations are not reported as unknown failures.
|
|
53
60
|
- Fixed native session cleanup paths to reject pending work before clearing provider state.
|
|
54
61
|
|
|
55
62
|
## 0.5.12 - 2026-05-13
|
|
56
63
|
|
|
57
|
-
### Changed
|
|
58
|
-
|
|
59
|
-
- Updated the Expo example to the current SDK 55 recommended `expo`, `expo-build-properties`, and `expo-system-ui` patch ranges.
|
|
60
|
-
|
|
61
64
|
### Fixed
|
|
62
65
|
|
|
63
|
-
- Fixed the Android example launcher icon by adding an adaptive icon foreground and dark brand background.
|
|
64
66
|
- Normalized web `SocialButton` and native login failures so presentation-anchor and missing-code errors surface as stable `AuthError` codes.
|
|
65
67
|
- Shipped package-level Watchman ignores for Android CMake cache output so consumers avoid noisy native build watcher events.
|
|
66
68
|
|
|
67
69
|
## 0.5.11 - 2026-05-05
|
|
68
70
|
|
|
69
|
-
### Changed
|
|
70
|
-
|
|
71
|
-
- Updated the Expo example to the Expo SDK 55 recommended `expo@~55.0.23` patch and Android API 36 target.
|
|
72
|
-
|
|
73
71
|
### Fixed
|
|
74
72
|
|
|
75
73
|
- Wrapped synchronous native service failures in `AuthError` so public service errors keep a consistent code contract.
|
|
76
74
|
|
|
77
|
-
### Verified
|
|
78
|
-
|
|
79
|
-
- `bun install --frozen-lockfile`
|
|
80
|
-
- `bunx expo install --check --cwd apps/example`
|
|
81
|
-
- `bunx expo-doctor@latest apps/example`
|
|
82
|
-
- `bun run check:ci`
|
|
83
|
-
- `bun run --cwd packages/react-native-nitro-auth test:coverage -- --runInBand`
|
|
84
|
-
- `bun run --cwd packages/react-native-nitro-auth test:cpp:coverage`
|
|
85
|
-
- `bun run example:prebuild`
|
|
86
|
-
- `bun run publish-package:dry-run`
|
|
87
|
-
|
|
88
75
|
## 0.5.10 - 2026-04-27
|
|
89
76
|
|
|
90
77
|
### Fixed
|
|
91
78
|
|
|
92
79
|
- Fixed iOS Microsoft sign-in so `ASWebAuthenticationSession` is retained until callback or cancellation and duplicate sessions fail with `operation_in_progress`.
|
|
93
|
-
- Fixed the example app header so it displays the current package version.
|
|
94
|
-
|
|
95
|
-
### Verified
|
|
96
|
-
|
|
97
|
-
- `bun run check:ci`
|
|
98
|
-
- `bunx expo install --check --cwd apps/example`
|
|
99
|
-
- `bunx expo-doctor@latest apps/example`
|
|
100
|
-
- `bun run example:prebuild`
|
|
101
|
-
- `bun run publish-package:dry-run`
|
|
102
80
|
|
|
103
81
|
## 0.5.9 - 2026-04-24
|
|
104
82
|
|
|
105
|
-
### Added
|
|
106
|
-
|
|
107
|
-
- Added shared JS service factory coverage and logger behavior tests.
|
|
108
|
-
- Added C++ coverage support with `test:cpp:coverage` and expanded native tests for session restore, token refresh, access-token fallback, scope updates, listener isolation, logout cancellation, and serializer behavior.
|
|
109
|
-
- Added example-app smoke checks for the public auth API, provider support, platform-gated behavior, and session-dependent methods.
|
|
110
|
-
|
|
111
83
|
### Changed
|
|
112
84
|
|
|
113
|
-
- Updated Expo SDK 55 patch dependencies, React Native 0.83.6, Nitro Modules 0.35.5
|
|
85
|
+
- Updated Expo SDK 55 patch dependencies, React Native 0.83.6, and Nitro Modules 0.35.5.
|
|
114
86
|
- Refactored native/web `AuthService` creation so native and web error mapping stay consistent.
|
|
115
87
|
- Hardened web OAuth state, cache parsing, token refresh, and provider error handling.
|
|
116
|
-
- Improved example app handling for unsupported providers and unavailable session actions.
|
|
117
|
-
- Improved release validation to include JS and C++ coverage gates and a faster publish dry run path.
|
|
118
88
|
|
|
119
89
|
### Fixed
|
|
120
90
|
|
|
121
|
-
- Fixed native runtime crashes in the example app when optional Nitro methods are not available on the installed native object.
|
|
122
|
-
- Fixed startup `silentRestore()` errors in the example app so restore failures surface in status instead of becoming unhandled promises.
|
|
123
91
|
- Excluded C++ test sources from the iOS pod target to avoid app-target duplicate `main` symbols.
|
|
124
|
-
|
|
125
|
-
### Verified
|
|
126
|
-
|
|
127
|
-
- `bun run check:ci`
|
|
128
|
-
- `bun run --cwd packages/react-native-nitro-auth test:coverage -- --runInBand`
|
|
129
|
-
- `bun run --cwd packages/react-native-nitro-auth test:cpp:coverage`
|
|
130
|
-
- `bun run publish-package:dry-run`
|
|
131
|
-
- `bun run example:prebuild`
|
|
132
|
-
- `bun run example:android`
|
|
133
|
-
- `bun run example:ios`
|
package/README.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# react-native-nitro-auth
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/react-native-nitro-auth)
|
|
4
|
+
[](https://www.npmjs.com/package/react-native-nitro-auth)
|
|
5
|
+
[](https://github.com/JoaoPauloCMarra/react-native-nitro-auth/actions/workflows/ci.yml)
|
|
4
6
|
[](https://github.com/JoaoPauloCMarra/react-native-nitro-auth/blob/main/LICENSE)
|
|
5
7
|
[](https://reactnative.dev/)
|
|
6
|
-
[](https://expo.dev/)
|
|
8
|
+
[](https://docs.expo.dev/)
|
|
7
9
|
[](https://nitro.margelo.com/)
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
8
11
|
|
|
9
12
|
Google Sign-In, Apple Sign-In, and Microsoft Entra ID for React Native and
|
|
10
13
|
Expo, powered by Nitro Modules.
|
|
@@ -113,15 +116,21 @@ path such as `contoso.onmicrosoft.com/B2C_1_signin`.
|
|
|
113
116
|
## Quick Start
|
|
114
117
|
|
|
115
118
|
```tsx
|
|
116
|
-
import {
|
|
119
|
+
import {
|
|
120
|
+
AuthService,
|
|
121
|
+
useAuth,
|
|
122
|
+
type ProviderLoginOptions,
|
|
123
|
+
} from "react-native-nitro-auth";
|
|
117
124
|
|
|
118
125
|
export function SignInButton() {
|
|
119
|
-
const { user, login, logout
|
|
126
|
+
const { user, login, logout } = useAuth();
|
|
120
127
|
|
|
121
128
|
async function signInWithGoogle() {
|
|
122
|
-
|
|
129
|
+
const options: ProviderLoginOptions<"google"> = {
|
|
123
130
|
scopes: ["openid", "profile", "email"],
|
|
124
|
-
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
await login("google", options);
|
|
125
134
|
}
|
|
126
135
|
|
|
127
136
|
if (user) {
|
|
@@ -131,8 +140,9 @@ export function SignInButton() {
|
|
|
131
140
|
return <Button title="Continue with Google" onPress={signInWithGoogle} />;
|
|
132
141
|
}
|
|
133
142
|
|
|
134
|
-
await AuthService.login(
|
|
143
|
+
await AuthService.login("microsoft", {
|
|
135
144
|
tenant: "organizations",
|
|
145
|
+
prompt: "select_account",
|
|
136
146
|
});
|
|
137
147
|
```
|
|
138
148
|
|
|
@@ -155,12 +165,39 @@ Main exports:
|
|
|
155
165
|
- `useAuth()` for React state, login, logout, refresh, and listeners.
|
|
156
166
|
- `AuthService` for imperative login, refresh, logout, and user reads.
|
|
157
167
|
- `SocialButton` for provider-aware UI.
|
|
158
|
-
- `AuthProvider` for
|
|
168
|
+
- `AuthProvider` for the `"google"`, `"apple"`, and `"microsoft"` provider names.
|
|
159
169
|
- `AuthError` and `AuthErrorCode` for deterministic failures.
|
|
160
170
|
- Provider option types for strongly typed login calls.
|
|
161
171
|
|
|
162
|
-
|
|
163
|
-
|
|
172
|
+
Provider-aware login calls reject unsupported option fields at compile time:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
import type {
|
|
176
|
+
ProviderLoginOptions,
|
|
177
|
+
MicrosoftLoginOptions,
|
|
178
|
+
} from "react-native-nitro-auth";
|
|
179
|
+
|
|
180
|
+
const googleOptions: ProviderLoginOptions<"google"> = {
|
|
181
|
+
scopes: ["openid", "email"],
|
|
182
|
+
hostedDomain: "company.com",
|
|
183
|
+
forceAccountPicker: true,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const microsoftOptions: MicrosoftLoginOptions = {
|
|
187
|
+
tenant: "organizations",
|
|
188
|
+
prompt: "select_account",
|
|
189
|
+
};
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Supported login options:
|
|
193
|
+
|
|
194
|
+
| Provider | Options |
|
|
195
|
+
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
196
|
+
| Google | `scopes`, `loginHint`, `nonce`, `forceAccountPicker`, `hostedDomain`, `useSheet`, `openIDRealm`, `useOneTap`, `filterByAuthorizedAccounts`, `useLegacyGoogleSignIn`, `forceCodeForRefreshToken`, `requestVerifiedPhoneNumber` |
|
|
197
|
+
| Apple | `scopes`, `nonce` |
|
|
198
|
+
| Microsoft | `scopes`, `loginHint`, `tenant`, `prompt` |
|
|
199
|
+
|
|
200
|
+
`prompt` is typed as `"login"`, `"consent"`, `"select_account"`, or `"none"`.
|
|
164
201
|
|
|
165
202
|
## Storage Model
|
|
166
203
|
|
|
@@ -174,8 +211,10 @@ server.
|
|
|
174
211
|
Async public APIs throw `AuthError` with a stable `code`, `provider`, `platform`,
|
|
175
212
|
and `message`. Use `instanceof AuthError` when branching in UI code.
|
|
176
213
|
|
|
177
|
-
|
|
178
|
-
`
|
|
214
|
+
Error codes are `cancelled`, `timeout`, `popup_blocked`, `network_error`,
|
|
215
|
+
`configuration_error`, `not_signed_in`, `operation_in_progress`,
|
|
216
|
+
`unsupported_provider`, `invalid_state`, `invalid_nonce`, `token_error`,
|
|
217
|
+
`no_id_token`, `parse_error`, `refresh_failed`, and `unknown`.
|
|
179
218
|
|
|
180
219
|
## Platform Support
|
|
181
220
|
|
|
@@ -47,7 +47,6 @@ object AuthAdapter {
|
|
|
47
47
|
private var currentActivity: Activity? = null
|
|
48
48
|
private var googleSignInClient: GoogleSignInClient? = null
|
|
49
49
|
private var lifecycleCallbacks: Application.ActivityLifecycleCallbacks? = null
|
|
50
|
-
private var pendingScopes: List<String> = emptyList()
|
|
51
50
|
private var pendingMicrosoftScopes: List<String> = emptyList()
|
|
52
51
|
|
|
53
52
|
@Volatile
|
|
@@ -212,7 +211,6 @@ object AuthAdapter {
|
|
|
212
211
|
}
|
|
213
212
|
|
|
214
213
|
val requestedScopes = scopes?.toList() ?: listOf("email", "profile")
|
|
215
|
-
pendingScopes = requestedScopes
|
|
216
214
|
|
|
217
215
|
if (useLegacyGoogleSignIn || forceAccountPicker) {
|
|
218
216
|
loginLegacy(context, clientId, requestedScopes, loginHint, forceAccountPicker, forceCodeForRefreshToken, hostedDomain, "login")
|
|
@@ -727,7 +725,7 @@ object AuthAdapter {
|
|
|
727
725
|
val ctx = appContext ?: context.applicationContext
|
|
728
726
|
val account = GoogleSignIn.getLastSignedInAccount(ctx)
|
|
729
727
|
if (account != null) {
|
|
730
|
-
|
|
728
|
+
val client = googleSignInClient ?: run {
|
|
731
729
|
val clientId = getClientIdFromResources(ctx)
|
|
732
730
|
if (clientId == null) {
|
|
733
731
|
nativeOnRefreshError("configuration_error", "Google Client ID not configured")
|
|
@@ -738,9 +736,11 @@ object AuthAdapter {
|
|
|
738
736
|
.requestServerAuthCode(clientId)
|
|
739
737
|
.requestEmail()
|
|
740
738
|
.build()
|
|
741
|
-
|
|
739
|
+
GoogleSignIn.getClient(ctx, gso).also {
|
|
740
|
+
googleSignInClient = it
|
|
741
|
+
}
|
|
742
742
|
}
|
|
743
|
-
|
|
743
|
+
client.silentSignIn().addOnCompleteListener { task ->
|
|
744
744
|
if (task.isSuccessful) {
|
|
745
745
|
val acc = task.result
|
|
746
746
|
nativeOnRefreshSuccess(acc?.idToken, null, getJwtExpirationTimeMs(acc?.idToken))
|
package/ios/AuthAdapter.swift
CHANGED
|
@@ -292,6 +292,21 @@ public class AuthAdapter: NSObject {
|
|
|
292
292
|
.replacingOccurrences(of: "/", with: "_")
|
|
293
293
|
.replacingOccurrences(of: "=", with: "")
|
|
294
294
|
}
|
|
295
|
+
|
|
296
|
+
private static let formUrlEncodedAllowedCharacters = CharacterSet(
|
|
297
|
+
charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
private static func formUrlEncodedBody(_ params: [String: String]) -> Data? {
|
|
301
|
+
params
|
|
302
|
+
.map { key, value in
|
|
303
|
+
let encodedKey = key.addingPercentEncoding(withAllowedCharacters: formUrlEncodedAllowedCharacters) ?? key
|
|
304
|
+
let encodedValue = value.addingPercentEncoding(withAllowedCharacters: formUrlEncodedAllowedCharacters) ?? value
|
|
305
|
+
return "\(encodedKey)=\(encodedValue)"
|
|
306
|
+
}
|
|
307
|
+
.joined(separator: "&")
|
|
308
|
+
.data(using: .utf8)
|
|
309
|
+
}
|
|
295
310
|
|
|
296
311
|
private static func exchangeCodeForTokens(
|
|
297
312
|
code: String,
|
|
@@ -322,10 +337,7 @@ public class AuthAdapter: NSObject {
|
|
|
322
337
|
"code_verifier": codeVerifier
|
|
323
338
|
]
|
|
324
339
|
|
|
325
|
-
request.httpBody = bodyParams
|
|
326
|
-
.map { "\($0.key)=\($0.value.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? $0.value)" }
|
|
327
|
-
.joined(separator: "&")
|
|
328
|
-
.data(using: .utf8)
|
|
340
|
+
request.httpBody = formUrlEncodedBody(bodyParams)
|
|
329
341
|
|
|
330
342
|
URLSession.shared.dataTask(with: request) { data, response, error in
|
|
331
343
|
DispatchQueue.main.async {
|
|
@@ -606,10 +618,7 @@ public class AuthAdapter: NSObject {
|
|
|
606
618
|
"refresh_token": refreshToken
|
|
607
619
|
]
|
|
608
620
|
|
|
609
|
-
request.httpBody = bodyParams
|
|
610
|
-
.map { "\($0.key)=\($0.value.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? $0.value)" }
|
|
611
|
-
.joined(separator: "&")
|
|
612
|
-
.data(using: .utf8)
|
|
621
|
+
request.httpBody = formUrlEncodedBody(bodyParams)
|
|
613
622
|
|
|
614
623
|
URLSession.shared.dataTask(with: request) { data, response, error in
|
|
615
624
|
DispatchQueue.main.async {
|
|
@@ -692,10 +701,7 @@ public class AuthAdapter: NSObject {
|
|
|
692
701
|
"grant_type": "refresh_token",
|
|
693
702
|
"refresh_token": refreshToken
|
|
694
703
|
]
|
|
695
|
-
request.httpBody = bodyParams
|
|
696
|
-
.map { "\($0.key)=\($0.value.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? $0.value)" }
|
|
697
|
-
.joined(separator: "&")
|
|
698
|
-
.data(using: .utf8)
|
|
704
|
+
request.httpBody = formUrlEncodedBody(bodyParams)
|
|
699
705
|
URLSession.shared.dataTask(with: request) { data, response, error in
|
|
700
706
|
DispatchQueue.main.async {
|
|
701
707
|
if error != nil {
|
package/lib/commonjs/Auth.web.js
CHANGED
|
@@ -43,6 +43,18 @@ const getOptionalNumber = (source, key) => {
|
|
|
43
43
|
const candidate = source[key];
|
|
44
44
|
return typeof candidate === "number" && Number.isFinite(candidate) ? candidate : undefined;
|
|
45
45
|
};
|
|
46
|
+
function setIfDefined(target, key, value) {
|
|
47
|
+
if (value !== undefined) {
|
|
48
|
+
target[key] = value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function setOrDelete(target, key, value) {
|
|
52
|
+
if (value === undefined) {
|
|
53
|
+
delete target[key];
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
target[key] = value;
|
|
57
|
+
}
|
|
46
58
|
const parseExpiresInSeconds = value => {
|
|
47
59
|
const candidate = typeof value === "number" ? value : typeof value === "string" && value.trim().length > 0 ? Number(value) : undefined;
|
|
48
60
|
if (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0) {
|
|
@@ -56,19 +68,20 @@ const parseAuthUser = value => {
|
|
|
56
68
|
}
|
|
57
69
|
const scopesCandidate = value.scopes;
|
|
58
70
|
const scopes = Array.isArray(scopesCandidate) ? scopesCandidate.filter(scope => typeof scope === "string") : undefined;
|
|
59
|
-
|
|
60
|
-
provider: value.provider
|
|
61
|
-
email: getOptionalString(value, "email"),
|
|
62
|
-
name: getOptionalString(value, "name"),
|
|
63
|
-
photo: getOptionalString(value, "photo"),
|
|
64
|
-
idToken: getOptionalString(value, "idToken"),
|
|
65
|
-
accessToken: getOptionalString(value, "accessToken"),
|
|
66
|
-
refreshToken: getOptionalString(value, "refreshToken"),
|
|
67
|
-
serverAuthCode: getOptionalString(value, "serverAuthCode"),
|
|
68
|
-
scopes,
|
|
69
|
-
expirationTime: getOptionalNumber(value, "expirationTime"),
|
|
70
|
-
underlyingError: getOptionalString(value, "underlyingError")
|
|
71
|
+
const user = {
|
|
72
|
+
provider: value.provider
|
|
71
73
|
};
|
|
74
|
+
setIfDefined(user, "email", getOptionalString(value, "email"));
|
|
75
|
+
setIfDefined(user, "name", getOptionalString(value, "name"));
|
|
76
|
+
setIfDefined(user, "photo", getOptionalString(value, "photo"));
|
|
77
|
+
setIfDefined(user, "idToken", getOptionalString(value, "idToken"));
|
|
78
|
+
setIfDefined(user, "accessToken", getOptionalString(value, "accessToken"));
|
|
79
|
+
setIfDefined(user, "refreshToken", getOptionalString(value, "refreshToken"));
|
|
80
|
+
setIfDefined(user, "serverAuthCode", getOptionalString(value, "serverAuthCode"));
|
|
81
|
+
setIfDefined(user, "scopes", scopes);
|
|
82
|
+
setIfDefined(user, "expirationTime", getOptionalNumber(value, "expirationTime"));
|
|
83
|
+
setIfDefined(user, "underlyingError", getOptionalString(value, "underlyingError"));
|
|
84
|
+
return user;
|
|
72
85
|
};
|
|
73
86
|
const parseScopes = value => {
|
|
74
87
|
if (!Array.isArray(value)) {
|
|
@@ -83,15 +96,15 @@ const parseAuthWebExtraConfig = value => {
|
|
|
83
96
|
}
|
|
84
97
|
const nitroAuthWebStorageCandidate = value.nitroAuthWebStorage;
|
|
85
98
|
const nitroAuthWebStorage = nitroAuthWebStorageCandidate === STORAGE_MODE_SESSION || nitroAuthWebStorageCandidate === STORAGE_MODE_LOCAL || nitroAuthWebStorageCandidate === STORAGE_MODE_MEMORY ? nitroAuthWebStorageCandidate : undefined;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
99
|
+
const config = {};
|
|
100
|
+
setIfDefined(config, "googleWebClientId", getOptionalString(value, "googleWebClientId"));
|
|
101
|
+
setIfDefined(config, "microsoftClientId", getOptionalString(value, "microsoftClientId"));
|
|
102
|
+
setIfDefined(config, "microsoftTenant", getOptionalString(value, "microsoftTenant"));
|
|
103
|
+
setIfDefined(config, "microsoftB2cDomain", getOptionalString(value, "microsoftB2cDomain"));
|
|
104
|
+
setIfDefined(config, "appleWebClientId", getOptionalString(value, "appleWebClientId"));
|
|
105
|
+
setIfDefined(config, "nitroAuthWebStorage", nitroAuthWebStorage);
|
|
106
|
+
setIfDefined(config, "nitroAuthPersistTokensOnWeb", typeof value.nitroAuthPersistTokensOnWeb === "boolean" ? value.nitroAuthPersistTokensOnWeb : undefined);
|
|
107
|
+
return config;
|
|
95
108
|
};
|
|
96
109
|
const getConfig = () => {
|
|
97
110
|
try {
|
|
@@ -507,19 +520,18 @@ class AuthWeb {
|
|
|
507
520
|
const claims = effectiveIdToken ? this.decodeMicrosoftJwt(effectiveIdToken) : {};
|
|
508
521
|
const user = {
|
|
509
522
|
...currentUser,
|
|
510
|
-
idToken: effectiveIdToken,
|
|
511
|
-
accessToken: accessToken ?? undefined,
|
|
512
|
-
refreshToken: newRefreshToken ?? currentUser.refreshToken,
|
|
513
|
-
expirationTime,
|
|
514
523
|
...claims
|
|
515
524
|
};
|
|
525
|
+
setOrDelete(user, "idToken", effectiveIdToken);
|
|
526
|
+
setOrDelete(user, "accessToken", accessToken);
|
|
527
|
+
setOrDelete(user, "refreshToken", newRefreshToken ?? currentUser.refreshToken);
|
|
528
|
+
setOrDelete(user, "expirationTime", expirationTime);
|
|
516
529
|
this.updateUser(user);
|
|
517
|
-
const tokens = {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
};
|
|
530
|
+
const tokens = {};
|
|
531
|
+
setIfDefined(tokens, "accessToken", accessToken);
|
|
532
|
+
setIfDefined(tokens, "idToken", effectiveIdToken);
|
|
533
|
+
setIfDefined(tokens, "refreshToken", newRefreshToken);
|
|
534
|
+
setIfDefined(tokens, "expirationTime", expirationTime);
|
|
523
535
|
this.notifyTokenListeners(tokens);
|
|
524
536
|
return tokens;
|
|
525
537
|
}
|
|
@@ -529,12 +541,11 @@ class AuthWeb {
|
|
|
529
541
|
_logger.logger.log("Refreshing tokens...");
|
|
530
542
|
await this.runLoginOperation(() => this.loginGoogle(this._grantedScopes.length > 0 ? this._grantedScopes : DEFAULT_SCOPES, undefined, undefined, generation));
|
|
531
543
|
this.assertActiveGeneration(generation);
|
|
532
|
-
const tokens = {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
};
|
|
544
|
+
const tokens = {};
|
|
545
|
+
setIfDefined(tokens, "accessToken", this._currentUser.accessToken);
|
|
546
|
+
setIfDefined(tokens, "idToken", this._currentUser.idToken);
|
|
547
|
+
setIfDefined(tokens, "refreshToken", this._currentUser.refreshToken);
|
|
548
|
+
setIfDefined(tokens, "expirationTime", this._currentUser.expirationTime);
|
|
538
549
|
this.notifyTokenListeners(tokens);
|
|
539
550
|
return tokens;
|
|
540
551
|
}
|
|
@@ -742,14 +753,14 @@ class AuthWeb {
|
|
|
742
753
|
const user = {
|
|
743
754
|
provider: "google",
|
|
744
755
|
idToken,
|
|
745
|
-
accessToken: accessToken ?? undefined,
|
|
746
|
-
serverAuthCode: code ?? undefined,
|
|
747
|
-
userId: getOptionalString(decoded, "sub"),
|
|
748
|
-
hostedDomain: getOptionalString(decoded, "hd"),
|
|
749
756
|
scopes,
|
|
750
|
-
expirationTime: this.getExpirationTime(expiresIn),
|
|
751
757
|
...this.decodeGoogleJwt(idToken)
|
|
752
758
|
};
|
|
759
|
+
setIfDefined(user, "accessToken", accessToken ?? undefined);
|
|
760
|
+
setIfDefined(user, "serverAuthCode", code ?? undefined);
|
|
761
|
+
setIfDefined(user, "userId", getOptionalString(decoded, "sub"));
|
|
762
|
+
setIfDefined(user, "hostedDomain", getOptionalString(decoded, "hd"));
|
|
763
|
+
setIfDefined(user, "expirationTime", this.getExpirationTime(expiresIn));
|
|
753
764
|
this.updateUser(user);
|
|
754
765
|
}).then(() => {
|
|
755
766
|
resolve();
|
|
@@ -761,13 +772,13 @@ class AuthWeb {
|
|
|
761
772
|
decodeGoogleJwt(token) {
|
|
762
773
|
try {
|
|
763
774
|
const decoded = this.parseJwtPayload(token);
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
775
|
+
const user = {};
|
|
776
|
+
setIfDefined(user, "email", getOptionalString(decoded, "email"));
|
|
777
|
+
setIfDefined(user, "name", getOptionalString(decoded, "name"));
|
|
778
|
+
setIfDefined(user, "photo", getOptionalString(decoded, "picture"));
|
|
779
|
+
setIfDefined(user, "userId", getOptionalString(decoded, "sub"));
|
|
780
|
+
setIfDefined(user, "hostedDomain", getOptionalString(decoded, "hd"));
|
|
781
|
+
return user;
|
|
771
782
|
} catch (error) {
|
|
772
783
|
_logger.logger.warn("Failed to decode Google ID token", {
|
|
773
784
|
error: String(error)
|
|
@@ -894,12 +905,12 @@ class AuthWeb {
|
|
|
894
905
|
const user = {
|
|
895
906
|
provider: "microsoft",
|
|
896
907
|
idToken,
|
|
897
|
-
accessToken: accessToken ?? undefined,
|
|
898
|
-
refreshToken: refreshToken ?? undefined,
|
|
899
908
|
scopes,
|
|
900
|
-
expirationTime: this.getExpirationTime(json["expires_in"]),
|
|
901
909
|
...claims
|
|
902
910
|
};
|
|
911
|
+
setIfDefined(user, "accessToken", accessToken);
|
|
912
|
+
setIfDefined(user, "refreshToken", refreshToken);
|
|
913
|
+
setIfDefined(user, "expirationTime", this.getExpirationTime(json["expires_in"]));
|
|
903
914
|
this.updateUser(user);
|
|
904
915
|
}
|
|
905
916
|
getMicrosoftAuthBaseUrl(tenant, b2cDomain) {
|
|
@@ -940,10 +951,10 @@ class AuthWeb {
|
|
|
940
951
|
decodeMicrosoftJwt(token) {
|
|
941
952
|
try {
|
|
942
953
|
const decoded = this.parseJwtPayload(token);
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
954
|
+
const user = {};
|
|
955
|
+
setIfDefined(user, "email", getOptionalString(decoded, "preferred_username") ?? getOptionalString(decoded, "email"));
|
|
956
|
+
setIfDefined(user, "name", getOptionalString(decoded, "name"));
|
|
957
|
+
return user;
|
|
947
958
|
} catch (error) {
|
|
948
959
|
_logger.logger.warn("Failed to decode Microsoft ID token", {
|
|
949
960
|
error: String(error)
|
|
@@ -1003,13 +1014,14 @@ class AuthWeb {
|
|
|
1003
1014
|
if (!window.AppleID) {
|
|
1004
1015
|
throw new Error("Apple SDK not loaded");
|
|
1005
1016
|
}
|
|
1006
|
-
|
|
1017
|
+
const appleAuthConfig = {
|
|
1007
1018
|
clientId,
|
|
1008
1019
|
scope: (options?.scopes?.length ? options.scopes : ["name", "email"]).join(" "),
|
|
1009
1020
|
redirectURI: window.location.origin,
|
|
1010
|
-
nonce: options?.nonce,
|
|
1011
1021
|
usePopup: true
|
|
1012
|
-
}
|
|
1022
|
+
};
|
|
1023
|
+
setIfDefined(appleAuthConfig, "nonce", options?.nonce);
|
|
1024
|
+
window.AppleID.auth.init(appleAuthConfig);
|
|
1013
1025
|
try {
|
|
1014
1026
|
const response = await window.AppleID.auth.signIn();
|
|
1015
1027
|
if (generation !== undefined) {
|
|
@@ -1017,11 +1029,11 @@ class AuthWeb {
|
|
|
1017
1029
|
}
|
|
1018
1030
|
const user = {
|
|
1019
1031
|
provider: "apple",
|
|
1020
|
-
idToken: response.authorization.id_token
|
|
1021
|
-
authorizationCode: response.authorization.code,
|
|
1022
|
-
email: response.user?.email,
|
|
1023
|
-
name: response.user?.name ? `${response.user.name.firstName} ${response.user.name.lastName}`.trim() : undefined
|
|
1032
|
+
idToken: response.authorization.id_token
|
|
1024
1033
|
};
|
|
1034
|
+
setIfDefined(user, "authorizationCode", response.authorization.code);
|
|
1035
|
+
setIfDefined(user, "email", response.user?.email);
|
|
1036
|
+
setIfDefined(user, "name", response.user?.name ? `${response.user.name.firstName} ${response.user.name.lastName}`.trim() : undefined);
|
|
1025
1037
|
this.updateUser(user);
|
|
1026
1038
|
} catch (error) {
|
|
1027
1039
|
throw this.mapError(error);
|