This project has moved. For the latest updates, please go here.

(Google) OpenID 2.0 migrating to OpenId Connect id's

Sep 10, 2014 at 8:17 AM
How can I get the old Open ID 2.0 id's with latest (v3.0.0.) pacages so that I can migrate id's and not have to force users to reconnect their external google account?

Google explains it here:

But I am wondering how I can do this with latest OWIN.Security.Google.GoogleOAuth2AuthenticationOptions?
Step 1.1 As Google describes I have to add an extra attribute openid.realm to the Authentication Request URI to Google... I did not find that the Google package has any support for this. But I managed to get it done with the following:
OnApplyRedirect = async context =>
    string redirect = context.RedirectUri + "&openid.realm=[OLD URI]";
But step 1.2 is tricky as I have to add signing-google at the end of the redirect URI i google developer console... so currently I am not getting the old id. Well, at least I don't think I am. Data is encryptet in a Cookie so I am not able to see what I am getting from Google. As I understand it the data is transferred via the ExternalCookie from Google to local Signin-google endpoint. The cookie seems to be encryted. Is there anyway to decrypt the data in the cookie? I would like to see what exactly I am getting from Google before Owin middleware touches it?

Is there no support for implementing the migration process?
I guess this is also related to this discussion:

According to this similar Stackoverflow question, the returned parameters should be in id_token, not the access token. I only see access token available in the OWIN context.
Sep 10, 2014 at 8:43 PM
You're actually the first to ask about any migration process. OpenID gave you so little user information that I don't think most people had anything to migrate.

First, about you trying to read the cookies. The best place to read the information sent from google is in GoogleOAuth2AuthenticationProvider.OnAuthenticated, GoogleOAuth2AuthenticatedContext.User. This event is called just before the information gets serialized into the cookie.

As noted in the related discussion, we do not attempt to preserve all of the user data in the ClaimsIdentity/Cookie. This is due in part to cookie size constraints. If there are specific fields you're interested in you should add them to the ClaimsIdentity in the OnAuthenticated event.

See if that gets you the information you're looking for.
Sep 19, 2014 at 8:59 AM
Well I want to migrate because I want to avoid asking all my users to reconnect with their Google account again.
With the old OpenId v2 the id's given by google was in a different format and domain specific then the id's that Google now gives out with OpenIdConnect.
So, like I said, the migration process is to avoid having asking users to reconnect their accounts. Which is a fair amount of users I might add.

I have look at the data in OnAuthenticated even but I am not getting the Id_Token (only access token) and therefore cannot find the extra field "OpenId" (old id).

Currently it looks as if I have to write my own loginprovider and not use OWIN as it seems you do not read the id_token?
Oct 15, 2014 at 6:41 PM
Some details on what is needed to obtain the OID2.0 ID. The openid.realm paramter as described previously is necessary. It might be nice to be able to specify the realm directly on the GoogleOAuth2AuthenticationOptions rather than having to go through the provider.

Then inside AuthenticateCoreAsync, the response object (JObject) returned from the TokenEndpoint will hold the id_token property. The value of the id_token is an encoded string that can be decoded with a System.IdentityModel.Tokens.JwtSecurityToken to expose the openid_id field inside. Currently, the id_token is being ignored.

It would be nice to have either the whole JWT or at least the openid_id value make its way into the GoogleOAuth2AuthenticatedContext somewhere. This will allow migrations to be performed during OnAuthenticate.
Nov 4, 2014 at 6:08 PM
We have the same problem with hundreds of users who will have be managed through the process of changing their credentials if we can't retrieve the old Open Id 2.0 id.

Tracher, can point to some documentation that shows how to add specific fields to the ClaimsIdentity in the OnAuthenticated event?
Nov 12, 2014 at 6:53 PM
Edited Nov 12, 2014 at 7:15 PM

We are a lot of people wandering aroung how to get this working with the Google middleware.

I open an issue and start a fork to fiddle with

My last commit would allow to do something like below. It is very simple (just adding some extra parameters).
builder.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions
                    SignInAsAuthenticationType = signAs,
                    AuthenticationType = "Google",
                    ClientId = "xxx",
                    ClientSecret = "xxx",
                    CallbackPath = PathString.FromUriComponent("/oauth2callback"),
                    OpenIdRealm = "",
                    Provider = new GoogleOAuth2AuthenticationProvider
                        OnAuthenticated = async context =>
                            IEnumerable<Claim> claims = null;
                                var jwtSecurityToken = new JwtSecurityToken(context.IdToken);
                                claims = jwtSecurityToken.Claims;
                            catch (ArgumentException) { }

                            if (claims != null)
                                var claim = claims.FirstOrDefault(c => c.Type == "openid_id");
                                if (claim != null)
                                    // add openid_id claim to the identity, so that it will be available in the callback url set when auth challenging like ExternalLoginCallback
                                    // callback will need to check existence of this claim and that the issuer is AuthenticationType (Google)
                                    context.Identity.AddClaim(new Claim("openid_id", claim.Value, claim.ValueType, context.Options.AuthenticationType));
Nov 15, 2014 at 11:48 AM

Just adding sample code to do the mapping. Assuming "OpenId" is the AuthenticationType for old OpenId.
 var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
            if (result == SignInStatus.Failure)
                // if failure and a Google mapping is present, try to find the user with the old openid id and replace it with the new one
                var googleOpenId =
                loginInfo.ExternalIdentity.Claims.FirstOrDefault(c => c.Issuer == "Google" && c.Type == "openid_id");
                if (googleOpenId != null)
                    var openIdLoginInfo = new UserLoginInfo("OpenId", googleOpenId.Value);
                    var user = await UserManager.FindAsync(openIdLoginInfo);
                    if (user != null)
                        var idResult = await UserManager.AddLoginAsync(user.Id, loginInfo.Login);
                        if (idResult.Succeeded)
                            await UserManager.RemoveLoginAsync(user.Id, openIdLoginInfo);
                           // retry signing, now it should find the user with the new openid connect id
                           result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);

            switch (result)
Nov 19, 2014 at 10:10 PM
Hey folks, we've got someone working on this.

Comments welcome.
Nov 20, 2014 at 6:45 PM
That's really great news.