PHP Classes

How to get google openid that matches the oauth id

Recommend this page to a friend!

      PHP OAuth Library  >  PHP OAuth Library package blog  >  How to Implement PHP ...  >  All threads  >  How to get google openid that...  >  (Un) Subscribe thread alerts  
Subject:How to get google openid that...
Summary:Google OpenId gave a url for an ID, but OAuth gives an integer
Messages:13
Author:sootsnoot
Date:2015-04-17 07:10:03
 
  1 - 10   11 - 13  

  1. How to get google openid that...   Reply   Report abuse  
Picture of sootsnoot sootsnoot - 2015-04-17 07:10:03
I've supported login with Google OpenID for a couple of years, now need to migrate to OAuth (ASAP - it came as a surprise to me).

My database contains user identifiers like 'https://www.google.com/accounts/o8/id?id=AItOa...LTkPu68'.

I've downloaded the package and got it working based on the login_with_google.php sample you provided - thanks for that, super helpful!

But the user information it returns just has a "sub" field with a value like '104919247341590724145', and I have no way to correlate it with the existing url-based ids.

According to https://developers.google.com/identity/protocols/OpenID2Migration#openid-connect "Step 3: Map OpenID 2.0 identifiers to OpenID Connect identifiers", if you pass an openid.realm parameter on the OpenID Connect authentication request, then when you get your access_token there should be an "openid_id" field in addition to the "sub" field, and that "openid_id" value will be the original openid identifier for the user, of the form "https://www.google.com/accounts/o8/id?id=xxxx"

But I haven't figured out any way to get that value using the oauth_client_class. My code looks like this:

$client->scope = 'openid email profile';
$success = $client->CallAPI(
"https://www.googleapis.com/oauth2/v3/userinfo",
'GET',
array('openid.realm'=>$client->redirect_uri),
array('FailOnAccessError'=>true), $user);

And the values coming back in $user are just:
email, email_verified, family_name, given_name, locale, name, picture, sub

Any suggestion how to get that openid_id value?


  2. Re: How to get google openid that...   Reply   Report abuse  
Picture of sootsnoot sootsnoot - 2015-04-17 07:34:45 - In reply to message 1 from sootsnoot
I failed to mention that I also tried calling the exact googleapi endpoint mentioned in that page:

$success = $client->CallAPI(
'https://www.googleapis.com/plus/v1/people/me/openIdConnect',
'GET',
array('openid.realm'=>$client->redirect_uri),
array('FailOnAccessError'=>true), $user);

The fields in $user are the same as described for userinfo, except for one additional field named 'kind', whose value is "plus#personOpenIdConnect"

  3. Re: How to get google openid that...   Reply   Report abuse  
Picture of Manuel Lemos Manuel Lemos - 2015-04-17 21:48:20 - In reply to message 1 from sootsnoot
Did you happen to use the script initially without the openid scope, and then changed it to add that scope?

In that case, the class obtains the token for the initial scopes and does not restart the process of getting a new token even if you change the scopes. So you may still be using a token without openid scope permissions.

You can restart the process calling ResetAccessToken function, so the class "forget" the previous token. Then you can restart the process with the openid scope and see if it works now as expected.

  4. Re: How to get google openid that...   Reply   Report abuse  
Picture of sootsnoot sootsnoot - 2015-04-18 06:47:05 - In reply to message 3 from Manuel Lemos
Thanks for the reply. I had actually originally started without the openid scope, but I had noticed that state was being preserved in the session. So I started clearing the session cookie in Chrome->Settings in between tests. Checking the code for ResetAccessToken, I see that all it really does is unset the OAUTH keys in the $_SESSION superglobal, clearing the session cookie gets rid of *all* the session state, so that's not the problem that's persisting.

Reading the web sites more carefully, I found two things that I thought might possibly be the problem:

1. The access_token endpoint listed in https://accounts.google.com/.well-known/openid-configuration was newer than the one hardcoded in oauth_client_class::Initialize(). Also that document contains a url for the authorization endpoint (which happened to be the same as the hardcoded one). So I modified oauth_client_class::Initialize() to use (new) class properties if they were already set in the class in preference to the hardcoded values. Then modified the calling code to set those properties with values obtained using curl on the ".well-known" url before calling Initialize().

2. According to https://developers.google.com/identity/protocols/OpenID2Migration, it looks like it's necessary to have the openid.realm parameter on the authentication request. So I added code to Initialize() to check for the existence of a class property name "realm", and if present append an openid.realm parameter to the dialog_url string (going through the GetDialogURL function to urlencode it).

Unfortunately, neither of these helped. No matter whether I call CallAPI on https://www.googleapis.com/oauth2/v1/userinfo or https://www.googleapis.com/plus/v1/people/me/openIdConnect, I still the the same results, with no 'openid_id' value, just the decimal integer 'sub' value along with the name and email, etc. [BTW, the ".well-known" document also specifies a newer version of the userinfo url than that hard-coded in the login_with_google example].

Have you ever seen an openid_id value returned from any of these APIs yourself, or have you seen any example of code that manages to produce one? As you well know, having managed to get this class working, the documentation is a little vague and spread out in places, and when you don't get the result you expect to get, there's not much to guide you on what you need to do to get that result! I'm really starting to tear my hair out on this...

Since I'm a new user here, I don't know the right way to post code. But since it's so short, and there are only two places where I made edits, I'll just try posting the modified sections of oauth_client_class here. Please let me know if you'd like me to do something else with the code. The changes didn't actually solve my problem, but might well be useful going forward.

1. Changed the "Google" case in Initialize to read:
case 'Google':
$this->oauth_version = '2.0';
if (empty($this->base_dialog_url)) {
$this->base_dialog_url = 'https://accounts.google.com/o/oauth2/auth';
}
$this->dialog_url = $this->base_dialog_url . '?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
if (! empty($this->realm)) {
$this->dialog_url .= '&openid.realm={REALM}';
}
$this->offline_dialog_url = $this->base_dialog_url . '?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}&access_type=offline&approval_prompt=force';
if (empty($this->access_token_url)) {
$this->access_token_url = 'https://accounts.google.com/o/oauth2/token';
}
break;


2. In GetDialogURL, changed the assignment to $url to read:
$url = str_replace(
'{REDIRECT_URI}', UrlEncode($redirect_uri), str_replace(
'{STATE}', UrlEncode($state), str_replace(
'{CLIENT_ID}', UrlEncode($this->client_id), str_replace(
'{API_KEY}', UrlEncode($this->api_key), str_replace(
'{SCOPE}', UrlEncode($this->scope), str_replace(
'{REALM}', UrlEncode($this->realm),
$url))))));

  5. Re: How to get google openid that...   Reply   Report abuse  
Picture of Manuel Lemos Manuel Lemos - 2015-04-19 03:29:32 - In reply to message 4 from sootsnoot
Since the endpoints and options seem to be different, it would be better to add a new OAuth server in the oauth_configuration.json file.

I am not yet familiar with OpenIDConnect but I understand that is basically OAuth 2.

So, if all you need to make it work is the realm variable, it would be simple to support it.

  6. Re: How to get google openid that...   Reply   Report abuse  
Picture of sootsnoot sootsnoot - 2015-04-19 04:11:49 - In reply to message 5 from Manuel Lemos
Ok, I didn't know about the json configuration file, I'll look into it.

In terms of the endpoints other than OpenIDConnect, that's just a question of using the ones that google "advertises" as being the current ones to use. Their documentation recommends getting their values from that ".well-known" url instead of hardcoding them, so that's what I did (using curl), and just set the values of the class variables to them before calling Initialize(). For purposes of maintaining the class, I think you should probably consider implementing an API to allow the user to set them. I'm guessing you might not want to have the class itself get the advertised endpoints for several reasons, like the user might not have the PHP curl extension available, and it would introduce an extra http round-trip to get them on each call to Initialize. Or maybe Initialize could take a parameter saying whether the class should fetch the current endpoints or use its own hard-coded values. Having the ".well-known" url hard-coded into the class seems like a good idea to me.

Sounds like the "realm" parameter is probably the thing that's most deserving of having a new server to handle it.

But unfortunately, I am still stumped in my attempt to get google to give me the old 'openid_id' for the user along with the new 'sub' value. One thing I found out only a couple of days ago is that the old openid id (urls of form https://www.google.com/accounts/o8/id?id=xxxxxxxxxxxxxxxxxx) are for a given user are actually different depending on the application. I'm not sure what the trigger is, but I think it's the value of the openid.realm parameter that causes different urls to be produced for the same google user; that's why the migration documentation tells you to make sure your redirect urls "match" (are compatible with) your old Openid realm value, and why it's necessary to pass in the openid.realm parameter in order to have google provide you with the old openid url in 'openid_id' in addition to the new 'sub' value. I think that the new 'sub' values differ for the same user based on the application key, instead of the realm.

I'm just amazed that I haven't been able to find any complete example showing that by doing "this, this, and this", you will get an 'openid_id' value in addition to the 'sub' value. It seems to me that it's an absolutely critical need for migrating - and where I'm having such trouble getting it, why has nobody else posted on it? I've scoured stackoverflow without success, guess I'll try asking the question directly.

  7. Re: How to get google openid that...   Reply   Report abuse  
Picture of Manuel Lemos Manuel Lemos - 2015-04-19 05:10:39 - In reply to message 6 from sootsnoot
I am not sure what you mean by .well-known.

Anyway, some OAuth servers return additional custom values when they return the access token.

You can enable the debug mode and see if the access token response is returning the openid_id you are looking for.

If that is the case, you can set the store_access_token_response variable to true, and get access to the values using the access_token_response variable.

Take a look at the login_with_salesforce.php for an example.

  8. Re: How to get google openid that...   Reply   Report abuse  
Picture of sootsnoot sootsnoot - 2015-04-19 06:16:48 - In reply to message 7 from Manuel Lemos
By ".well-known", I was referring to post 3 in this thread:
"1. The access_token endpoint listed in https://accounts.google.com/.well-known/openid-configuration...".

That url comes from "The Discovery document" section of https://developers.google.com/identity/protocols/OpenIDConnect


Thanks for the tip about store_access_token_response. But unfortunately, the only values stored are token_type, id_token, access_token, expires_in. I decoded the id_token value with https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=<string>, but there was no openid_id value in there, either.

FYI, I've posted this question in stackoverflow: http://stackoverflow.com/questions/29726093/google-openidconnect-why-am-i-not-getting-an-openid-id-value-along-with-sub

  9. Re: How to get google openid that...   Reply   Report abuse  
Picture of Manuel Lemos Manuel Lemos - 2015-04-19 06:37:58 - In reply to message 8 from sootsnoot
Oh, I got it, it is for discovery of endpoints and other things.

For OpenID they used to use XRDS.

I may implement a script in the future to discover values for endpoints for servers without built-in support.

I figure it would not make much sense to include that in the class because discovery slows down everything and even with caching would make the class bloated.

I think it is better to have a separate script to figure the values for the users to add to oauth_configuration.json.

As for your problem, I suppose somebody from Google will follow-up there some time later. If they post a solution, it would be nice if you post your conclusions here, in case other people find this thread looking for the same thing.

  10. Re: How to get google openid that...   Reply   Report abuse  
Picture of sootsnoot sootsnoot - 2015-04-19 13:45:36 - In reply to message 9 from Manuel Lemos
Yup. I'll certainly post back here. I really do appreciate both the code you've provided to the community, and your responsive support! Thank you.

 
  1 - 10   11 - 13