'iOS Google SignIn refreshed idToken has missing profile info in backend authentication
I use GoogleSignIn for iOS (GoogleSignIn-iOS), v6.1.0, in my iOS app. All calls to my backend have the idToken in the request header. The id token is verified in the backend. Here I also need to retrieve the users email and name. (see also: https://developers.google.com/identity/sign-in/ios/backend-auth)
After a new SignIn with GIDSignIn.sharedInstance.signIn
everything works fine.
GIDSignIn.sharedInstance.currentUser.profile
contains email and name.
When sending the idToken to the backend, the Verifier gives me name and email in its payload, too.
Before I do a backend request, I get a valid (=not expired) idToken, with the following code:
private static func refreshToken(_ authentication: GIDAuthentication) async throws -> GIDAuthentication {
try await withCheckedThrowingContinuation { continuation in
authentication.do { authentication, error in
if let authentication = authentication {
continuation.resume(returning: authentication)
} else if let error = error {
Log.warn("Google SignIn refreshToken failed with -> \(error)")
continuation.resume(throwing: error)
}
}
}
}
I use the following code to get the idToken, before I create the request for my URLSession.
func idToken() async -> String {
do {
guard let user = GIDSignIn.sharedInstance.currentUser else {
Log.error("No GID user to get idToken from")
return ""
}
currentAuth = try await Self.refreshToken(user.authentication) //currentAuth is a class variable
return currentAuth?.idToken ?? ""
} catch {
print("Error during Google SignIn idToken retrieval \(error)")
return ""
}
}
And now my problem comes:
The idToken is refreshed properly. It is valid for another hour, and the verifier in my backend accepts it.
But I can't get the users name from the verified payload data in the backend, the name field is null
.
Same happens when I use GIDSignIn.sharedInstance.restorePreviousSignIn
(which I call on every app re-start, to do the silent sign in. (But in the app, the values are there in the updated users object profile)
It seems to me, that when the idToken gets refreshed, that it looses the profile scope.
I hope someone can help me with this, or at least explain the behaviour to me.
Thank in advance :)
Update
- I checked the idTokens on https://jwt.io.
They are valid, but after the refresh, the jwt payload definitely is missing the profile data, like the users name. - I waited one day and tried again. Now the silent signin after app start gives me a complete idToken with jwt payload including name, but only once. After an hour, when the idToken gets refreshed, the idToken is again missing the profile information
Solution 1:[1]
Unfortunately I got no hint here, so I solved my problem as follows.
I hope this approach can save time for some others in the future.
I only require the profile data, when the user logs in to the backend the first time and a new user record is created in the backend.
In all other calls, where I need the JWT for authentication, I only rely on the basic information (ID, email) and handle all other values as optional values.
So I check the users name, if it is available. Otherwise the ID and a valid token is of course sufficent for authentication.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | CDoubleU |