I'm trying to setup Google Sign in for both my Android and iOS app.
The Google login is configured in the apps and should send the id token retrieved in the app to the server. The PHP code on serverside should then use the Google Client to verify the Id token that is sent using the following code:
$client = new Google_Client(['client_id' => $CLIENT_ID]);
try{
$payload = $client->verifyIdToken($request["idToken"]);
} catch(Exception $e){
api_error("ID verification failed E1; ".$e->getMessage(), 304);
}
if($payload) {
$sid = "G".$payload['sub'];
} else {
api_error("ID verification failed E2;", 304);
}
However, while this code verifies the idtoken sent by me Android app successfully it fails when sending the idtoken from the iOS app. The payload variable returns null and always reaches the ID verification failed E2 part of the code.
Debugging the idtoken that is sent from the mobile devices in the REST api endpoint https://www.googleapis.com/oauth2/v3/tokeninfo?id_token= gives me a successfull response for both Android and iOS. The only difference I can discover in the response is the azp and aud values. Given the apps use different client ids I assume this difference is as expected.
On the Android code the Google SDK has the requestIdToken(webClientId) method which allows you to set the web client id variable in order to request the id token. For the iOS Google Sign In I cannot find the option to set the web client id. I tried to set the webClientId in as the serverClientId in the GIDSignIn.sharedInstance() but this gives me a 400 error telling me the audience is invalid.
Is there a way to set this webclientid and is there a requestIdToken equivalent for iOS? I'm currently using the following code to obtain the idtoken on iOS:
@IBOutlet weak var googLoginButton: GIDSignInButton!
@IBOutlet weak var fbLoginButton: FBSDKLoginButton!
let tokenValidation = TokenValidation();
var isShown = false;
override func viewDidLoad() {
super.viewDidLoad()
fbLoginButton.delegate = self;
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().uiDelegate = self
}
The TokenValidation class is a custom class that I wrote to send the data to the server.
The ViewController has a GIDSignInButton that calls the following function:
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!,
withError error: Error!) {
if (error == nil) {
let idToken = user.authentication.idToken
tokenValidation.setFBAccessToken(accessToken: nil);
tokenValidation.setGoogleIdToken(googleIdToken: idToken);
startTokenValidate(tokenValidation: tokenValidation);
} else {
showMessage(messageStr: error.localizedDescription);
}
}
The startTokenValidate function then calls my API endpoint to verify the token. The error variable inside the app is always nil.
Is there any way to retrieve a correct idtoken or are there any alternatives to validate the Google Sign In with the backend server?
In my case, it is because the client ID in my .env file does not match the
audvalue returned by the Google API when iOS token is sent. The client ID set in my .env only matches with theaudreturned for Android token. I don't know the best practice for this. Maybe you need to have different API client for different platform, which is instantiated with different client ID. But my simple solution is, I just omit any argument while creating the client, like this:Looking at the source code of Google API client, when the client ID is not set, it will skip checking the
audvalue. Again, there might be better and more secure way to do this but this is what I did with mine.