Skip to content

Issue obtaining a valid JWT from Google Oauth2 Sign in #6849

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

Open
REPTILEHAUS opened this issue Aug 7, 2020 · 26 comments
Open

Issue obtaining a valid JWT from Google Oauth2 Sign in #6849

REPTILEHAUS opened this issue Aug 7, 2020 · 26 comments
Labels
type:bug Impaired feature or lacking behavior that is likely assumed type:docs Only change in the docs or README

Comments

@REPTILEHAUS
Copy link

Im using your Google Auth adapter for web login. my call to google yields an access_token (rather than ID token), the token is not a standard JWT and looks like the following : ya29.a0AfH6SMDBFlJErplnG3niNU_qksL9yyOfbbYJO5DF7uDPGVpIx4ef6CEBfxZ00QBDdDeLtOQsPQqzz57tn7AUwHxhO0vT0Lg49spIsaWgVkE_lWmhC29Kgcl-DueDWFdS8f57w5KLFusqvLtwlLCkNfAZIeqgJN6Kg_2

It seems that Google have updated their Oauth2 APIs, I also see you have updated your Google auth provider however it doesnt accept this as a valid JWT, is there some other way to authenticate with Google and Parse now ?

https://developers.google.com/identity/protocols/oauth2

@mtrezza
Copy link
Member

mtrezza commented Aug 7, 2020

Thanks for reporting.

@SebC99 since you are familiar with #6734, do you have any suggestion why this fails?

@REPTILEHAUS
Copy link
Author

From what I can see your auth adapter is using Oauth and expecting a id_token JWT. My app receives an OpenID access_token which is not a valid JWT

@REPTILEHAUS
Copy link
Author

In your docs is mentions 2 flows for google, one using the id_token and one using access_token however your adapter only appears to handle the id_token flow https://github.com/parse-community/parse-server/blob/master/src/Adapters/Auth/google.js

@REPTILEHAUS
Copy link
Author

The old code worked because it validated both id_tokens and access_tokens independently- access tokens are not JWTs so when the latest commit tries to validate them it doesn’t work, I believe the difference here is that id_token is provided by OAuth whereas access_token is from OpenID protocol

@REPTILEHAUS
Copy link
Author

I will fork and use the old Google adapter as a workaround

@SebC99
Copy link
Contributor

SebC99 commented Aug 8, 2020

I have to admit I don’t understand why there’s sometimes id_token and sometimes access_token. The google documentation isn’t clear at all about this.
The link you provided is about client use, and there’s nothing about token verification in it.
We could add a method for access_token that just saves it in auth_data without any kind of verification.
Or I could use the old “development verification” of the old adapter for access_token.
If someone finds the right way to check access_token in production I would be happy to do it

@SebC99
Copy link
Contributor

SebC99 commented Aug 8, 2020

As far as I can see the response from google when exchanging an authorization code for a token contains both access token and id token:
https://developers.google.com/identity/protocols/oauth2/openid-connect#exchangecode
You don’t observe this @REPTILEHAUS ?

@REPTILEHAUS
Copy link
Author

I use another 3rd party plugin for handling OAuth2 login https://github.com/moberwasserlechner/capacitor-oauth2, it all worked seamlessly up until a month ago and I see they have had an updated code base and you guys did too, however I havent fully reviewed their code yet to see if there was a breaking change, all I noticed was that passing the token to parse fails with invalid JWT as its the access_token now being returned rather than the id_token

@REPTILEHAUS
Copy link
Author

I guess either way they maybe should be handled separately as the Parse docs specify that either id_token or access_token can be used as 2 different flows

 https://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication 

{
  "google": {
    "id": "user's Google id (string)",
    "id_token": "an authorized Google id_token for the user (use when not using access_token)",
    "access_token": "an authorized Google access_token for the user (use when not using id_token)"
  }
}

@mtrezza mtrezza added type:bug Impaired feature or lacking behavior that is likely assumed troubleshooting and removed troubleshooting type:bug Impaired feature or lacking behavior that is likely assumed labels Aug 9, 2020
@REPTILEHAUS
Copy link
Author

I have to admit I don’t understand why there’s sometimes id_token and sometimes access_token. The google documentation isn’t clear at all about this.
The link you provided is about client use, and there’s nothing about token verification in it.
We could add a method for access_token that just saves it in auth_data without any kind of verification.
Or I could use the old “development verification” of the old adapter for access_token.
If someone finds the right way to check access_token in production I would be happy to do it

Token verifications is done by firing an external http request to one of Googles endpoints for either access_token or id_token, I think this is how you did it before more info https://stackoverflow.com/questions/359472/how-can-i-verify-a-google-authentication-api-access-token

I reviewed that Oauth2 Plugin and no code has changed so the issue is with the latest Parse, I downgraded and Authentication is working as it should

@SebC99
Copy link
Contributor

SebC99 commented Aug 10, 2020

Yes, and in the official link showed in your SO link (first answer) it is written:

An easy way to validate an ID token signature for debugging is to use the tokeninfo endpoint. Calling this endpoint involves an additional network request that does most of the validation for you while you test proper validation and payload extraction in your own code. It is not suitable for use in production code as requests may be throttled or otherwise subject to intermittent errors.

Plus, there's only info about id_token and not access_token in the Google page (https://developers.google.com/identity/sign-in/android/backend-auth)

When looking at the first link your provided (https://developers.google.com/identity/protocols/oauth2/), there's no backend verification involved, except for the openID protocol, where you can get the id_token as well (https://developers.google.com/identity/protocols/oauth2/openid-connect#exchangecode)
It's also written in another answer of your SO question.

The difference between access_token and id_token is explained a bit here:
https://stackoverflow.com/a/49385979

Isn't there any way you can get the id_token as specified in the doc?

NB: The parse documentation is not up to date, and I think there's already a PR about it.

@mtrezza
Copy link
Member

mtrezza commented Sep 3, 2020

@REPTILEHAUS, @SebC99 Is this still an issue? Is this actually a bug in Parse Server or just in the docs?

@SebC99
Copy link
Contributor

SebC99 commented Sep 3, 2020

For me it's a doc issue, as the only valid verification described in google doc (for production) is with id_token.
access_token with openID should be exchanged for id_token as described by Google doc

@nopol10
Copy link

nopol10 commented Sep 28, 2020

While the id_token is definitely the right way to authenticate the user, would it be possible to allow a configurable option in the google auth adapter to accept an access_token to check against Google's development endpoint (as it used to be done)? Asking this as I have a particular use case in which using the id_token will lead to a bad user experience:

I'm intending to let users use Google login via a Chrome extension. To obtain an id_token in an extension, I have to use the launchWebAuthFlow method in Chrome's identity API. The login data is only stored until Chrome is closed. The user will then have to relogin with their email and password the next time Chrome is opened (authing with this method will not let users select directly from their logged in Google profiles in Chrome). This is obviously not great for the user.

Chrome's identity api also provides the getAuthToken method which does let users pick from a logged in Google account (great for UX, 1 click login), however it currently can only return an access token. There have been requests for the id_token to be returned from the api but nothing has been done for years.

I've also looked into whether it is possible to get an id_token from an access_token (basically do a getAuthToken and then call another endpoint with the result to get an id_token to pass to Parse) but have come up with nothing so far.

Might be an obscure use case but just wanted to share it.

@REPTILEHAUS
Copy link
Author

@mtrezza sorry missed your comment, yes its still an issue, I reverted to the old implementation as a fix

@SebC99
Copy link
Contributor

SebC99 commented Sep 28, 2020

@nopol10 it's very easy to add back the development endpoint for access_token if it's really needed, yes.
I just don't know if these cases are supposed to be handled by Parse official adapter, or by a custom adapter you could use

@nopol10
Copy link

nopol10 commented Sep 28, 2020

Yup, I'm probably going to use the old code as a custom adapter if I have to update from 4.2. It makes sense for the official adapter to support just the official methods I suppose

@REPTILEHAUS
Copy link
Author

It should probably be added back anyway for legacy app support

@mtrezza
Copy link
Member

mtrezza commented Nov 3, 2020

Would anyone be willing to open a PR for the suggested changes?

I will classify this as a bug because - as I understand - a recent change has removed the development endpoint for access_token which turned out to be a breaking change in this special case. Even if an endpoint is merely for development purposes, it can be part of a CI / development process and therefore cause a breaking change. Whether a development endpoint is “misused” in a production setting would be irrelevant I guess.

@mtrezza mtrezza added type:bug Impaired feature or lacking behavior that is likely assumed type:docs Only change in the docs or README and removed 🔧 troubleshooting labels Nov 3, 2020
@SebC99
Copy link
Contributor

SebC99 commented Nov 3, 2020

@mtrezza it's not the real reason as I explained. Google documentation says access_token (with openID) should be exchanged for id_token and then used with Parse Google Auth. So we shouldn't really deal with access_token in Parse. But I can add back this old behavior of course

@mtrezza
Copy link
Member

mtrezza commented Nov 3, 2020

@SebC99 thanks for clarifying, let me go through this thread again and see what I’ve missed.

@REPTILEHAUS
Copy link
Author

REPTILEHAUS commented Dec 22, 2020

Guys this is still an issue, Im trying to setup another Parse project using latest version and getting this ID token invalid problem, when will this be fixed, Ive had to revert to the old parse for 2 projects now. I could do a PR but probably better if the one who added the issue fixes it at last.

@mtrezza
Copy link
Member

mtrezza commented Dec 22, 2020

I believe there is already #6992 that fixes this? @SebC99 do you recall why the PR is in draft state?

@RodrigoSMarques
Copy link

RodrigoSMarques commented Dec 22, 2020

I am using authentication with a Flutter application with parse server 4.4.0.

After several searches, I solved the problem by adding "default_web_client_id" in strings.xml for Android.

This identifier I created at https://console.cloud.google.com/ creating an OAuth 2.0 client IDs for Android.

{
  "google": {
    "id": "1166077090183XXXXXXXX",
    "id_token": "eyJhbGciOiJSUzI1N.......",
    "access_token": "ya29..........."
  }
}

@SebC99
Copy link
Contributor

SebC99 commented Dec 22, 2020

@mtrezza not at all, maybe just because of the coverage decrease?

@oliamb
Copy link

oliamb commented Mar 12, 2023

The interface from Google evolved, and the code I tried tonight works. But is it secure?

import { GoogleLogin } from "@react-oauth/google";
import { User } from "parse";
import jwt from "jwt-decode";

function App() {
  const responseMessage = async (response) => {
    const payload = jwt(response.credential);
    const user = new User();
    await user.linkWith("google", {
      authData: {
        id: payload.sub,
        id_token: response.credential,
      },
    });
    user.set("username", payload.name);
    user.set("email", payload.email);
    const res = await user.save();
    console.log("Login Success");
  };
  const errorMessage = (error) => {
    console.log(error);
  };
  return (
    <div className="App">
          <main>
            <GoogleLogin onSuccess={responseMessage} onError={errorMessage} />
          </main>
    </div>
  );
}

export default App;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:bug Impaired feature or lacking behavior that is likely assumed type:docs Only change in the docs or README
Projects
None yet
Development

No branches or pull requests

6 participants