-
Notifications
You must be signed in to change notification settings - Fork 703
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Google Sign-In: GoogleIdTokenVerifier.verify returns null for a valid id token #2343
Comments
Hi @idrisadetunmbi, thanks for bringing this up. |
@clundin25, thanks for your answer, but I still don't get what the correct usage should be. I decoded a JWT retrieved from the client (through the Google Sign-in Android SDK) and the audience is actually a string and not a list which means the code only checks if that single string audience is in one of the "trustedClientIds". My expectation of the flow is that the verifier takes the list of trusted mobile client ids, and when it is verifying an id token, it checks that the aud (of the id token is one of them), but the aud that seems to be in the id token is the server's web client id and not the mobile client id. |
You want to verify the audience from the server is what you expect it to be. |
Ping! I came here to report the same thing. And... I'm also confused about what to do here... I can confirm that my client ID is the Android client ID (and not the Web) for the backend/server side. Also, I manually de-coded the ID token and can confirm that the aud, iss, exp should be valid, it's only the signature that I can't be sure is valid or not - but I'm not sure why it wouldn't be. Here's my code: SignInCredential credential = oneTapClient.getSignInCredentialFromIntent(result.getData());
String unverifiedIdToken = credential.getGoogleIdToken(); // a JWT token
if (unverifiedIdToken != null) {
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), new GsonFactory())
.setAudience(Collections.singletonList(getString(R.string.android_client_id)))
.build();
try {
GoogleIdToken idToken = verifier.verify(unverifiedIdToken); // null
... Decoding the JWT token manually, I successfully managed to get a header and payload but I didn't get a signature... I'm not sure if that's expected behaviour or not tbh, in the documentation they mention that "The ID token is properly signed by Google" so I assumed I would be able to get the signature after decoding. They also mentioned two public keys which I assume we were supposed to use at some point for the missing signature. |
Well @idrisadetunmbi it's been 2 weeks now, did you find a solution to this? |
Hi @DaTigerYT. For now, I just specified the web client id (meant for the server) as part of the client ids when initializing the verifier. The problem could also be from the client and not the verifier, but I have not had the time to verify this. |
I don't do it often, but I just ran my code in debug mode and I noticed something pretty interesting... as shown in the screenshots below, after the verifier does |
Finally got the thing to work, I should mention: .setAudience() seems to accept the web_client_id (for the front end) rather than the android_client_id (supposed to be for the backend), again this is highly likely because the aud and azp are mysteriously switched for some reason. Not only that, when using Arrays.asList() as long as one of the strings is the web client ID it will work but you can also just get rid of setAudience() together and it'll work. For those in the future who may be reading this: After that, I was faced with a GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
.setAudience(Collections.singleton(getString(R.string.web_client_id)))
.build();
try {
return verifier.verify(unverifiedIdToken);
// Put code here to do after verification here After: ExecutorService executor = Executors.newSingleThreadExecutor();
Future<GoogleIdToken> future = executor.submit(() -> {
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), new GsonFactory())
.setAudience(Collections.singletonList("WEB_CLIENT_ID")) // or just get rid of the setAudience entirely for some reason
.build();
try {
return verifier.verify(unverifiedIdToken);
} catch (GeneralSecurityException | IOException e) {
e.printStackTrace();
return null;
}
});
executor.execute(() -> {
GoogleIdToken idToken = null;
try {
idToken = future.get(); // This will block until the task is done
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// Put code here to do after verification here
executor.shutdown(); // Shut down the executor after the task is done
}); Hopefully that helped someone... if only Google just updated their damn documentation haha |
Hopefully there isn't a security risk in the mix when not specifying the audience or specifying the web client id as one of the audience. Another option is to use the verifier without the audience but check that the azp from the |
Thanks for diving deep into this @DaTigerYT. We will take a closer look at this |
oh and by the way, if you put your client-id in a property, make sure you don't have it as a string there. just discovered that in my project. 😄 |
If anyone is currently experiencing the Error 400: redirect_uri_mismatch error when using oauth2 for access to Google APIs. It's likely because the issue was fixed and thus you should now use your web_client_id (as opposed to the android_client_id) like originally intended. |
@DaTigerYT Thank you very much for your answer; it worked after I changed 'audience' to 'WEB_CLIENT_ID'. |
Environment details
Description
I am integrating the Google sign-in and authenticating the id token on the backend as described here. The documentation for the
GoogleIdTokenVerifier
states to specify the client ids of apps (the mobile apps I believe) when instantiating the class, but when I callGoogleIdTokenVerifier.verify
on the idToken (returned from the flow with the mobile app), it returnsnull
(meaning the idToken is invalid). Specifying the web client id (which is for the server) however, works. Can this be clarified, please? Which client ids are meant to be specified when instantiating the class?Steps to reproduce
Same steps as described here
Code example
Stack trace
NA
External references such as API reference guides
https://developers.google.com/identity/sign-in/android/backend-auth
Any additional information below
NA
The text was updated successfully, but these errors were encountered: