react-native-nitro-auth 0.5.12 → 0.6.1
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 +42 -0
- package/README.md +132 -32
- package/android/build.gradle +4 -4
- package/android/gradle.properties +2 -2
- package/android/src/main/cpp/PlatformAuth+Android.cpp +87 -4
- package/android/src/main/java/com/auth/AuthAdapter.kt +85 -48
- package/android/src/main/java/com/auth/GoogleSignInActivity.kt +12 -2
- package/cpp/HybridAuth.cpp +168 -18
- package/cpp/HybridAuth.hpp +7 -0
- package/cpp/PlatformAuth.hpp +1 -0
- package/ios/AuthAdapter.swift +101 -24
- package/ios/PlatformAuth+iOS.mm +37 -1
- package/lib/commonjs/Auth.web.js +74 -21
- package/lib/commonjs/Auth.web.js.map +1 -1
- package/lib/commonjs/create-auth-service.js +10 -0
- package/lib/commonjs/create-auth-service.js.map +1 -1
- package/lib/commonjs/index.js +12 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +12 -0
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/provider-options.js +6 -0
- package/lib/commonjs/provider-options.js.map +1 -0
- package/lib/commonjs/service.js.map +1 -1
- package/lib/commonjs/service.web.js.map +1 -1
- package/lib/commonjs/use-auth.js +21 -1
- package/lib/commonjs/use-auth.js.map +1 -1
- package/lib/module/Auth.web.js +74 -21
- package/lib/module/Auth.web.js.map +1 -1
- package/lib/module/create-auth-service.js +10 -0
- package/lib/module/create-auth-service.js.map +1 -1
- package/lib/module/global.d.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +1 -0
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/provider-options.js +4 -0
- package/lib/module/provider-options.js.map +1 -0
- package/lib/module/service.js.map +1 -1
- package/lib/module/service.web.js.map +1 -1
- package/lib/module/use-auth.js +21 -1
- package/lib/module/use-auth.js.map +1 -1
- package/lib/typescript/commonjs/Auth.nitro.d.ts +11 -0
- package/lib/typescript/commonjs/Auth.nitro.d.ts.map +1 -1
- package/lib/typescript/commonjs/Auth.web.d.ts +4 -0
- package/lib/typescript/commonjs/Auth.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/create-auth-service.d.ts +2 -1
- package/lib/typescript/commonjs/create-auth-service.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +1 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +1 -0
- package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/provider-options.d.ts +23 -0
- package/lib/typescript/commonjs/provider-options.d.ts.map +1 -0
- package/lib/typescript/commonjs/service.d.ts +2 -2
- package/lib/typescript/commonjs/service.d.ts.map +1 -1
- package/lib/typescript/commonjs/service.web.d.ts +2 -2
- package/lib/typescript/commonjs/service.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/use-auth.d.ts +4 -2
- package/lib/typescript/commonjs/use-auth.d.ts.map +1 -1
- package/lib/typescript/module/Auth.nitro.d.ts +11 -0
- package/lib/typescript/module/Auth.nitro.d.ts.map +1 -1
- package/lib/typescript/module/Auth.web.d.ts +4 -0
- package/lib/typescript/module/Auth.web.d.ts.map +1 -1
- package/lib/typescript/module/create-auth-service.d.ts +2 -1
- package/lib/typescript/module/create-auth-service.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +1 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/index.web.d.ts +1 -0
- package/lib/typescript/module/index.web.d.ts.map +1 -1
- package/lib/typescript/module/provider-options.d.ts +23 -0
- package/lib/typescript/module/provider-options.d.ts.map +1 -0
- package/lib/typescript/module/service.d.ts +2 -2
- package/lib/typescript/module/service.d.ts.map +1 -1
- package/lib/typescript/module/service.web.d.ts +2 -2
- package/lib/typescript/module/service.web.d.ts.map +1 -1
- package/lib/typescript/module/use-auth.d.ts +4 -2
- package/lib/typescript/module/use-auth.d.ts.map +1 -1
- package/nitrogen/generated/shared/c++/AuthUser.hpp +17 -1
- package/nitrogen/generated/shared/c++/HybridAuthSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridAuthSpec.hpp +1 -0
- package/nitrogen/generated/shared/c++/LoginOptions.hpp +25 -1
- package/package.json +7 -7
- package/react-native-nitro-auth.podspec +1 -1
- package/src/Auth.nitro.ts +11 -0
- package/src/Auth.web.ts +99 -16
- package/src/create-auth-service.ts +19 -9
- package/src/global.d.ts +2 -1
- package/src/index.ts +1 -0
- package/src/index.web.ts +1 -0
- package/src/provider-options.ts +62 -0
- package/src/service.ts +2 -1
- package/src/service.web.ts +2 -2
- package/src/use-auth.ts +22 -8
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
@file:Suppress("DEPRECATION")
|
|
2
|
-
// The legacy com.google.android.gms.auth.api.signin.* API is used intentionally for:
|
|
3
|
-
// • getLastSignedInAccount – persists session across app restarts via GMS store; no drop-in replacement
|
|
4
|
-
// • silentSignIn – AuthorizationClient.authorize() still requires an Activity for interactive fallback
|
|
5
|
-
// • revokeAccess – no equivalent in Credential Manager or Identity.getAuthorizationClient()
|
|
6
|
-
// All modern entry-points use Credential Manager (One-Tap) unless the caller explicitly needs
|
|
7
|
-
// Android's account chooser semantics, which still require the legacy Google Sign-In flow.
|
|
8
2
|
|
|
9
3
|
package com.auth
|
|
10
4
|
|
|
@@ -33,6 +27,7 @@ import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
|
|
|
33
27
|
import kotlinx.coroutines.CoroutineScope
|
|
34
28
|
import kotlinx.coroutines.Dispatchers
|
|
35
29
|
import kotlinx.coroutines.SupervisorJob
|
|
30
|
+
import kotlinx.coroutines.CancellationException
|
|
36
31
|
import kotlinx.coroutines.cancel
|
|
37
32
|
import kotlinx.coroutines.launch
|
|
38
33
|
import kotlinx.coroutines.withContext
|
|
@@ -71,6 +66,8 @@ object AuthAdapter {
|
|
|
71
66
|
private var pendingMicrosoftB2cDomain: String? = null
|
|
72
67
|
@Volatile
|
|
73
68
|
private var microsoftAuthInProgress = false
|
|
69
|
+
@Volatile
|
|
70
|
+
private var hasLegacyGoogleSession = false
|
|
74
71
|
|
|
75
72
|
@Volatile
|
|
76
73
|
private var inMemoryMicrosoftRefreshToken: String? = null
|
|
@@ -78,7 +75,6 @@ object AuthAdapter {
|
|
|
78
75
|
private var inMemoryMicrosoftScopes: List<String> =
|
|
79
76
|
defaultMicrosoftScopes
|
|
80
77
|
|
|
81
|
-
// Module-scoped coroutine scope — cancelled on module invalidation via dispose().
|
|
82
78
|
private var moduleScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
|
83
79
|
|
|
84
80
|
@JvmStatic
|
|
@@ -96,6 +92,9 @@ object AuthAdapter {
|
|
|
96
92
|
idToken: String?,
|
|
97
93
|
accessToken: String?,
|
|
98
94
|
serverAuthCode: String?,
|
|
95
|
+
userId: String?,
|
|
96
|
+
phoneNumber: String?,
|
|
97
|
+
hostedDomain: String?,
|
|
99
98
|
scopes: Array<String>?,
|
|
100
99
|
expirationTime: Long?
|
|
101
100
|
)
|
|
@@ -131,9 +130,6 @@ object AuthAdapter {
|
|
|
131
130
|
}
|
|
132
131
|
|
|
133
132
|
try {
|
|
134
|
-
// The native library is already loaded by NitroAuthOnLoad.initializeNative()
|
|
135
|
-
// before this method is called from NitroAuthModule. We only need to wire
|
|
136
|
-
// the Android context so that native methods can call back into the JVM.
|
|
137
133
|
nativeInitialize(applicationContext)
|
|
138
134
|
isInitialized = true
|
|
139
135
|
} catch (e: Exception) {
|
|
@@ -159,10 +155,11 @@ object AuthAdapter {
|
|
|
159
155
|
|
|
160
156
|
fun onSignInSuccess(account: GoogleSignInAccount, scopes: List<String>, origin: String = "login") {
|
|
161
157
|
appContext ?: return
|
|
158
|
+
hasLegacyGoogleSession = true
|
|
162
159
|
val expirationTime = getJwtExpirationTimeMs(account.idToken)
|
|
163
160
|
nativeOnLoginSuccess(origin, "google", account.email, account.displayName,
|
|
164
161
|
account.photoUrl?.toString(), account.idToken, null, account.serverAuthCode,
|
|
165
|
-
scopes.toTypedArray(), expirationTime)
|
|
162
|
+
account.id, null, null, scopes.toTypedArray(), expirationTime)
|
|
166
163
|
}
|
|
167
164
|
|
|
168
165
|
fun onSignInError(errorCode: Int, message: String?, origin: String = "login") {
|
|
@@ -182,11 +179,17 @@ object AuthAdapter {
|
|
|
182
179
|
googleClientId: String?,
|
|
183
180
|
scopes: Array<String>?,
|
|
184
181
|
loginHint: String?,
|
|
182
|
+
nonce: String?,
|
|
185
183
|
useOneTap: Boolean,
|
|
186
184
|
forceAccountPicker: Boolean = false,
|
|
187
185
|
useLegacyGoogleSignIn: Boolean = false,
|
|
186
|
+
filterByAuthorizedAccounts: Boolean = false,
|
|
187
|
+
forceCodeForRefreshToken: Boolean = false,
|
|
188
|
+
requestVerifiedPhoneNumber: Boolean = false,
|
|
188
189
|
tenant: String? = null,
|
|
189
|
-
prompt: String? = null
|
|
190
|
+
prompt: String? = null,
|
|
191
|
+
hostedDomain: String? = null,
|
|
192
|
+
openIDRealm: String? = null
|
|
190
193
|
) {
|
|
191
194
|
if (provider == "apple") {
|
|
192
195
|
nativeOnLoginError("login", "unsupported_provider", "Apple Sign-In is not supported on Android.")
|
|
@@ -212,10 +215,10 @@ object AuthAdapter {
|
|
|
212
215
|
pendingScopes = requestedScopes
|
|
213
216
|
|
|
214
217
|
if (useLegacyGoogleSignIn || forceAccountPicker) {
|
|
215
|
-
loginLegacy(context, clientId, requestedScopes, loginHint, forceAccountPicker, "login")
|
|
218
|
+
loginLegacy(context, clientId, requestedScopes, loginHint, forceAccountPicker, forceCodeForRefreshToken, hostedDomain, "login")
|
|
216
219
|
return
|
|
217
220
|
}
|
|
218
|
-
loginOneTap(context, clientId, requestedScopes, loginHint, forceAccountPicker, useOneTap, "login")
|
|
221
|
+
loginOneTap(context, clientId, requestedScopes, loginHint, nonce, forceAccountPicker, useOneTap, filterByAuthorizedAccounts, requestVerifiedPhoneNumber, hostedDomain, "login")
|
|
219
222
|
}
|
|
220
223
|
|
|
221
224
|
private fun loginMicrosoft(context: Context, scopes: Array<String>?, loginHint: String?, tenant: String?, prompt: String?, origin: String = "login") {
|
|
@@ -377,6 +380,8 @@ object AuthAdapter {
|
|
|
377
380
|
} finally {
|
|
378
381
|
connection.disconnect()
|
|
379
382
|
}
|
|
383
|
+
} catch (e: CancellationException) {
|
|
384
|
+
clearPkceState()
|
|
380
385
|
} catch (e: Exception) {
|
|
381
386
|
withContext(Dispatchers.Main) {
|
|
382
387
|
clearPkceState()
|
|
@@ -432,7 +437,7 @@ object AuthAdapter {
|
|
|
432
437
|
clearPkceState()
|
|
433
438
|
nativeOnLoginSuccess(
|
|
434
439
|
origin, "microsoft", email, name, null, idToken, accessToken, null,
|
|
435
|
-
grantedScopes.toTypedArray(), expirationTime
|
|
440
|
+
null, null, null, grantedScopes.toTypedArray(), expirationTime
|
|
436
441
|
)
|
|
437
442
|
} catch (e: Exception) {
|
|
438
443
|
clearPkceState()
|
|
@@ -440,6 +445,30 @@ object AuthAdapter {
|
|
|
440
445
|
}
|
|
441
446
|
}
|
|
442
447
|
|
|
448
|
+
private fun clearCredentialManagerState(context: Context) {
|
|
449
|
+
moduleScope.launch {
|
|
450
|
+
try {
|
|
451
|
+
CredentialManager.create(context).clearCredentialState(ClearCredentialStateRequest())
|
|
452
|
+
} catch (e: Exception) {
|
|
453
|
+
Log.w(TAG, "clearCredentialState failed: ${e.message}")
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
private fun getLegacyGoogleClient(context: Context): GoogleSignInClient? {
|
|
459
|
+
val clientId = getClientIdFromResources(context) ?: return null
|
|
460
|
+
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
|
|
461
|
+
.requestIdToken(clientId)
|
|
462
|
+
.requestServerAuthCode(clientId)
|
|
463
|
+
.requestEmail()
|
|
464
|
+
.build()
|
|
465
|
+
return GoogleSignIn.getClient(context, gso)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
private fun hasLegacyGoogleAccount(context: Context): Boolean {
|
|
469
|
+
return hasLegacyGoogleSession || GoogleSignIn.getLastSignedInAccount(context) != null
|
|
470
|
+
}
|
|
471
|
+
|
|
443
472
|
@Synchronized
|
|
444
473
|
private fun clearPkceState() {
|
|
445
474
|
pendingOrigin = "login"
|
|
@@ -487,6 +516,11 @@ object AuthAdapter {
|
|
|
487
516
|
return expSeconds * 1000
|
|
488
517
|
}
|
|
489
518
|
|
|
519
|
+
private fun hostedDomainFromEmail(email: String?): String? {
|
|
520
|
+
val parts = email?.split("@", limit = 2) ?: return null
|
|
521
|
+
return parts.getOrNull(1)
|
|
522
|
+
}
|
|
523
|
+
|
|
490
524
|
private fun getMicrosoftClientIdFromResources(context: Context): String? {
|
|
491
525
|
val resId = context.resources.getIdentifier("nitro_auth_microsoft_client_id", "string", context.packageName)
|
|
492
526
|
return if (resId != 0) context.getString(resId) else null
|
|
@@ -518,21 +552,30 @@ object AuthAdapter {
|
|
|
518
552
|
clientId: String,
|
|
519
553
|
scopes: List<String>,
|
|
520
554
|
loginHint: String?,
|
|
555
|
+
nonce: String?,
|
|
521
556
|
forceAccountPicker: Boolean,
|
|
522
557
|
useOneTap: Boolean,
|
|
558
|
+
filterByAuthorizedAccounts: Boolean,
|
|
559
|
+
requestVerifiedPhoneNumber: Boolean,
|
|
560
|
+
hostedDomain: String?,
|
|
523
561
|
origin: String = "login"
|
|
524
562
|
) {
|
|
525
563
|
val activity = currentActivity ?: context as? Activity
|
|
526
564
|
if (activity == null) {
|
|
527
565
|
Log.w(TAG, "No Activity context available for One-Tap, falling back to legacy")
|
|
528
|
-
return loginLegacy(context, clientId, scopes, loginHint, forceAccountPicker, origin)
|
|
566
|
+
return loginLegacy(context, clientId, scopes, loginHint, forceAccountPicker, false, hostedDomain, origin)
|
|
529
567
|
}
|
|
530
568
|
|
|
531
569
|
val credentialManager = CredentialManager.create(activity)
|
|
532
570
|
val googleIdOption = GetGoogleIdOption.Builder()
|
|
533
|
-
.setFilterByAuthorizedAccounts(
|
|
571
|
+
.setFilterByAuthorizedAccounts(filterByAuthorizedAccounts)
|
|
534
572
|
.setServerClientId(clientId)
|
|
535
573
|
.setAutoSelectEnabled(useOneTap && !forceAccountPicker)
|
|
574
|
+
.setRequestVerifiedPhoneNumber(requestVerifiedPhoneNumber)
|
|
575
|
+
.apply {
|
|
576
|
+
if (nonce != null) setNonce(nonce)
|
|
577
|
+
if (hostedDomain != null) setHostedDomainFilter(hostedDomain)
|
|
578
|
+
}
|
|
536
579
|
.build()
|
|
537
580
|
|
|
538
581
|
val request = GetCredentialRequest.Builder()
|
|
@@ -543,9 +586,11 @@ object AuthAdapter {
|
|
|
543
586
|
try {
|
|
544
587
|
val result = credentialManager.getCredential(context = activity, request = request)
|
|
545
588
|
handleCredentialResponse(result, scopes, origin)
|
|
589
|
+
} catch (e: CancellationException) {
|
|
590
|
+
return@launch
|
|
546
591
|
} catch (e: Exception) {
|
|
547
592
|
Log.w(TAG, "One-Tap failed, falling back to legacy: ${e.message}")
|
|
548
|
-
loginLegacy(context, clientId, scopes, loginHint, forceAccountPicker, origin)
|
|
593
|
+
loginLegacy(context, clientId, scopes, loginHint, forceAccountPicker, false, hostedDomain, origin)
|
|
549
594
|
}
|
|
550
595
|
}
|
|
551
596
|
}
|
|
@@ -556,11 +601,13 @@ object AuthAdapter {
|
|
|
556
601
|
scopes: List<String>,
|
|
557
602
|
loginHint: String?,
|
|
558
603
|
forceAccountPicker: Boolean,
|
|
604
|
+
forceCodeForRefreshToken: Boolean,
|
|
605
|
+
hostedDomain: String?,
|
|
559
606
|
origin: String = "login"
|
|
560
607
|
) {
|
|
561
608
|
val ctx = appContext ?: context.applicationContext
|
|
562
609
|
val intent = GoogleSignInActivity.createIntent(
|
|
563
|
-
ctx, clientId, scopes.toTypedArray(), loginHint, forceAccountPicker, origin
|
|
610
|
+
ctx, clientId, scopes.toTypedArray(), loginHint, forceAccountPicker, forceCodeForRefreshToken, hostedDomain, origin
|
|
564
611
|
)
|
|
565
612
|
intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
566
613
|
ctx.startActivity(intent)
|
|
@@ -585,11 +632,14 @@ object AuthAdapter {
|
|
|
585
632
|
val expirationTime = getJwtExpirationTimeMs(googleIdTokenCredential.idToken)
|
|
586
633
|
nativeOnLoginSuccess(
|
|
587
634
|
origin, "google",
|
|
588
|
-
googleIdTokenCredential.
|
|
635
|
+
googleIdTokenCredential.email,
|
|
589
636
|
googleIdTokenCredential.displayName,
|
|
590
637
|
googleIdTokenCredential.profilePictureUri?.toString(),
|
|
591
638
|
googleIdTokenCredential.idToken,
|
|
592
639
|
null, null,
|
|
640
|
+
googleIdTokenCredential.id,
|
|
641
|
+
googleIdTokenCredential.phoneNumber,
|
|
642
|
+
hostedDomainFromEmail(googleIdTokenCredential.email),
|
|
593
643
|
scopes.toTypedArray(),
|
|
594
644
|
expirationTime
|
|
595
645
|
)
|
|
@@ -599,8 +649,6 @@ object AuthAdapter {
|
|
|
599
649
|
}
|
|
600
650
|
}
|
|
601
651
|
|
|
602
|
-
// requestScopesSync uses the legacy GoogleSignIn API to check the last signed-in account
|
|
603
|
-
// because Credential Manager has no equivalent for querying existing account state.
|
|
604
652
|
@JvmStatic
|
|
605
653
|
fun requestScopesSync(context: Context, scopes: Array<String>) {
|
|
606
654
|
val ctx = appContext ?: context.applicationContext
|
|
@@ -631,8 +679,6 @@ object AuthAdapter {
|
|
|
631
679
|
nativeOnLoginError("scopes", "not_signed_in", "No user logged in")
|
|
632
680
|
}
|
|
633
681
|
|
|
634
|
-
// refreshTokenSync uses the legacy silentSignIn because AuthorizationClient (the recommended
|
|
635
|
-
// replacement) requires an Activity context which is not always available at refresh time.
|
|
636
682
|
@JvmStatic
|
|
637
683
|
fun refreshTokenSync(context: Context) {
|
|
638
684
|
val ctx = appContext ?: context.applicationContext
|
|
@@ -676,27 +722,14 @@ object AuthAdapter {
|
|
|
676
722
|
.isGooglePlayServicesAvailable(ctx) == ConnectionResult.SUCCESS
|
|
677
723
|
}
|
|
678
724
|
|
|
679
|
-
// revokeAccessSync uses the legacy GoogleSignIn client because Credential Manager has no
|
|
680
|
-
// equivalent revoke API for the Google ID token flow.
|
|
681
725
|
@JvmStatic
|
|
682
726
|
fun logoutSync(context: Context) {
|
|
683
727
|
val ctx = appContext ?: context.applicationContext
|
|
684
728
|
clearPkceState()
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
try {
|
|
688
|
-
CredentialManager.create(ctx).clearCredentialState(ClearCredentialStateRequest())
|
|
689
|
-
} catch (e: Exception) {
|
|
690
|
-
Log.w(TAG, "clearCredentialState failed: ${e.message}")
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
// Also clear legacy GMS sign-in state so getLastSignedInAccount returns null.
|
|
694
|
-
val clientId = getClientIdFromResources(ctx)
|
|
695
|
-
if (clientId != null) {
|
|
696
|
-
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
|
|
697
|
-
.requestIdToken(clientId).requestEmail().build()
|
|
698
|
-
GoogleSignIn.getClient(ctx, gso).signOut()
|
|
729
|
+
if (hasLegacyGoogleAccount(ctx)) {
|
|
730
|
+
getLegacyGoogleClient(ctx)?.signOut()
|
|
699
731
|
}
|
|
732
|
+
hasLegacyGoogleSession = false
|
|
700
733
|
inMemoryMicrosoftRefreshToken = null
|
|
701
734
|
inMemoryMicrosoftScopes = defaultMicrosoftScopes
|
|
702
735
|
}
|
|
@@ -705,12 +738,11 @@ object AuthAdapter {
|
|
|
705
738
|
fun revokeAccessSync(context: Context) {
|
|
706
739
|
val ctx = appContext ?: context.applicationContext
|
|
707
740
|
clearPkceState()
|
|
708
|
-
|
|
709
|
-
if (
|
|
710
|
-
|
|
711
|
-
.requestIdToken(clientId).requestServerAuthCode(clientId).requestEmail().build()
|
|
712
|
-
GoogleSignIn.getClient(ctx, gso).revokeAccess()
|
|
741
|
+
clearCredentialManagerState(ctx)
|
|
742
|
+
if (hasLegacyGoogleAccount(ctx)) {
|
|
743
|
+
getLegacyGoogleClient(ctx)?.revokeAccess()
|
|
713
744
|
}
|
|
745
|
+
hasLegacyGoogleSession = false
|
|
714
746
|
inMemoryMicrosoftRefreshToken = null
|
|
715
747
|
inMemoryMicrosoftScopes = defaultMicrosoftScopes
|
|
716
748
|
}
|
|
@@ -726,10 +758,11 @@ object AuthAdapter {
|
|
|
726
758
|
@Suppress("DEPRECATION")
|
|
727
759
|
val account = GoogleSignIn.getLastSignedInAccount(ctx)
|
|
728
760
|
if (account != null) {
|
|
761
|
+
hasLegacyGoogleSession = true
|
|
729
762
|
val expirationTime = getJwtExpirationTimeMs(account.idToken)
|
|
730
763
|
nativeOnLoginSuccess("silent", "google", account.email, account.displayName,
|
|
731
764
|
account.photoUrl?.toString(), account.idToken, null, account.serverAuthCode,
|
|
732
|
-
account.grantedScopes?.map { it.scopeUri }?.toTypedArray(), expirationTime)
|
|
765
|
+
account.id, null, null, account.grantedScopes?.map { it.scopeUri }?.toTypedArray(), expirationTime)
|
|
733
766
|
} else {
|
|
734
767
|
val refreshToken = inMemoryMicrosoftRefreshToken
|
|
735
768
|
if (refreshToken != null) {
|
|
@@ -795,10 +828,10 @@ object AuthAdapter {
|
|
|
795
828
|
nativeOnLoginSuccess("silent", "microsoft",
|
|
796
829
|
claims["preferred_username"] ?: claims["email"],
|
|
797
830
|
claims["name"], null,
|
|
798
|
-
newIdToken, newAccessToken, null, effectiveScopes.toTypedArray(), expirationTime)
|
|
831
|
+
newIdToken, newAccessToken, null, null, null, null, effectiveScopes.toTypedArray(), expirationTime)
|
|
799
832
|
} else {
|
|
800
833
|
if (responseCode in 400..499) {
|
|
801
|
-
inMemoryMicrosoftRefreshToken = null
|
|
834
|
+
inMemoryMicrosoftRefreshToken = null
|
|
802
835
|
}
|
|
803
836
|
val mappedError = try {
|
|
804
837
|
val json = org.json.JSONObject(responseBody)
|
|
@@ -814,6 +847,8 @@ object AuthAdapter {
|
|
|
814
847
|
} finally {
|
|
815
848
|
connection.disconnect()
|
|
816
849
|
}
|
|
850
|
+
} catch (e: CancellationException) {
|
|
851
|
+
nativeOnLoginError("silent", "cancelled", e.message)
|
|
817
852
|
} catch (e: Exception) {
|
|
818
853
|
withContext(Dispatchers.Main) {
|
|
819
854
|
nativeOnLoginError("silent", "network_error", e.message)
|
|
@@ -897,6 +932,8 @@ object AuthAdapter {
|
|
|
897
932
|
} finally {
|
|
898
933
|
connection.disconnect()
|
|
899
934
|
}
|
|
935
|
+
} catch (e: CancellationException) {
|
|
936
|
+
nativeOnRefreshError("cancelled", e.message)
|
|
900
937
|
} catch (e: Exception) {
|
|
901
938
|
withContext(Dispatchers.Main) {
|
|
902
939
|
nativeOnRefreshError("network_error", e.message)
|
|
@@ -21,14 +21,18 @@ class GoogleSignInActivity : ComponentActivity() {
|
|
|
21
21
|
private const val EXTRA_SCOPES = "scopes"
|
|
22
22
|
private const val EXTRA_LOGIN_HINT = "login_hint"
|
|
23
23
|
private const val EXTRA_FORCE_PICKER = "force_picker"
|
|
24
|
+
private const val EXTRA_FORCE_CODE_FOR_REFRESH_TOKEN = "force_code_for_refresh_token"
|
|
25
|
+
private const val EXTRA_HOSTED_DOMAIN = "hosted_domain"
|
|
24
26
|
private const val EXTRA_ORIGIN = "origin"
|
|
25
27
|
|
|
26
|
-
fun createIntent(context: Context, clientId: String, scopes: Array<String>, loginHint: String?, forcePicker: Boolean = false, origin: String = "login"): Intent {
|
|
28
|
+
fun createIntent(context: Context, clientId: String, scopes: Array<String>, loginHint: String?, forcePicker: Boolean = false, forceCodeForRefreshToken: Boolean = false, hostedDomain: String? = null, origin: String = "login"): Intent {
|
|
27
29
|
return Intent(context, GoogleSignInActivity::class.java).apply {
|
|
28
30
|
putExtra(EXTRA_CLIENT_ID, clientId)
|
|
29
31
|
putExtra(EXTRA_SCOPES, scopes)
|
|
30
32
|
putExtra(EXTRA_LOGIN_HINT, loginHint)
|
|
31
33
|
putExtra(EXTRA_FORCE_PICKER, forcePicker)
|
|
34
|
+
putExtra(EXTRA_FORCE_CODE_FOR_REFRESH_TOKEN, forceCodeForRefreshToken)
|
|
35
|
+
putExtra(EXTRA_HOSTED_DOMAIN, hostedDomain)
|
|
32
36
|
putExtra(EXTRA_ORIGIN, origin)
|
|
33
37
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
34
38
|
}
|
|
@@ -56,6 +60,8 @@ class GoogleSignInActivity : ComponentActivity() {
|
|
|
56
60
|
val scopes = intent.getStringArrayExtra(EXTRA_SCOPES) ?: arrayOf("email", "profile")
|
|
57
61
|
val loginHint = intent.getStringExtra(EXTRA_LOGIN_HINT)
|
|
58
62
|
val forcePicker = intent.getBooleanExtra(EXTRA_FORCE_PICKER, false)
|
|
63
|
+
val forceCodeForRefreshToken = intent.getBooleanExtra(EXTRA_FORCE_CODE_FOR_REFRESH_TOKEN, false)
|
|
64
|
+
val hostedDomain = intent.getStringExtra(EXTRA_HOSTED_DOMAIN)
|
|
59
65
|
|
|
60
66
|
val origin = intent.getStringExtra(EXTRA_ORIGIN) ?: "login"
|
|
61
67
|
if (clientId == null) {
|
|
@@ -66,8 +72,12 @@ class GoogleSignInActivity : ComponentActivity() {
|
|
|
66
72
|
|
|
67
73
|
val gsoBuilder = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
|
|
68
74
|
.requestIdToken(clientId)
|
|
69
|
-
.requestServerAuthCode(clientId)
|
|
75
|
+
.requestServerAuthCode(clientId, forceCodeForRefreshToken)
|
|
70
76
|
.requestEmail()
|
|
77
|
+
|
|
78
|
+
if (hostedDomain != null) {
|
|
79
|
+
gsoBuilder.setHostedDomain(hostedDomain)
|
|
80
|
+
}
|
|
71
81
|
|
|
72
82
|
scopes.forEach { scopeStr ->
|
|
73
83
|
if (scopeStr != "email" && scopeStr != "profile" && scopeStr != "openid") {
|