11package expo.modules.clerk.googlesignin
22
3+ import android.util.Base64
34import androidx.credentials.ClearCredentialStateRequest
45import androidx.credentials.CredentialManager
56import androidx.credentials.CustomCredential
@@ -18,6 +19,7 @@ import expo.modules.kotlin.modules.ModuleDefinition
1819import kotlinx.coroutines.CoroutineScope
1920import kotlinx.coroutines.Dispatchers
2021import kotlinx.coroutines.launch
22+ import org.json.JSONObject
2123
2224class ClerkGoogleSignInModule : Module () {
2325 private var webClientId: String? = null
@@ -221,6 +223,15 @@ class ClerkGoogleSignInModule : Module() {
221223 promise.reject(" SIGN_IN_CANCELLED" , exception.message ? : " User cancelled the sign-in flow" , exception)
222224 }
223225
226+ // GoogleIdTokenCredential.id is the email, so the stable account ID has to come from the token's sub claim.
227+ private fun subjectFromIdToken (idToken : String ): String? {
228+ val payload = idToken.split(" ." ).getOrNull(1 ) ? : return null
229+ return runCatching {
230+ val json = String (Base64 .decode(payload, Base64 .URL_SAFE or Base64 .NO_WRAP or Base64 .NO_PADDING ))
231+ JSONObject (json).optString(" sub" ).takeIf { it.isNotEmpty() }
232+ }.getOrNull()
233+ }
234+
224235 private fun handleSignInResult (result : GetCredentialResponse , promise : Promise ) {
225236 when (val credential = result.credential) {
226237 is CustomCredential -> {
@@ -229,7 +240,7 @@ class ClerkGoogleSignInModule : Module() {
229240 val googleIdTokenCredential = GoogleIdTokenCredential .createFrom(credential.data)
230241
231242 val user = mapOf (
232- " id" to googleIdTokenCredential.id ,
243+ " id" to (subjectFromIdToken( googleIdTokenCredential.idToken) ? : " " ) ,
233244 " email" to googleIdTokenCredential.id,
234245 " name" to googleIdTokenCredential.displayName,
235246 " givenName" to googleIdTokenCredential.givenName,
0 commit comments