I have begun the process of Migrating from Google OpenID to the OpenID Connect with OAuth 2.0 following what is presented in the Documentation. I am able successfully complete the workflow of retrieving the openid_id and sub inside the id_token from the token endpoint, but when I do, the openid_id does not match the existing identifier we have in our system. Preventing me from mapping the existing user to the new ID and preventing the user from logging into our application (or possibly being allowed to log in as someone else). the id is of the correct format, but just doesn't match.
I have set the openid.realm parameter to our existing openid.realm as well as setting the redirect the same as suggested by the documentation. This is happening both locally and in our azure hosted environments. I am using the JWT.JsonWebToken to decode the id_token but I also verified that it was being decoded properly by using the web hosted decoder on google: JWT Decoder, and I came up with the same OpenID Identifier that did not match the one we currently have for that user. I should also note that I have tried adding the profile scope as well but that did not make any difference.
We are using DotNetOpenAuth.OpenId for our original system, so I don't think the problem lies there. I have examined the ClaimedIdentifier that is part of the response and it does match what we save in our system for openId so we are not saving it incorrectly.
Below is the what we use to generate the Uri for the auth request. It is mostly a modified version of the DotNetOpenAuth.GoogleOAuth2 client.
protected static Uri GetServiceLoginUrl(Uri returnUrl)
{
var state = string.IsNullOrEmpty(returnUrl.Query) ? string.Empty : returnUrl.Query.Substring(1);
return BuildUri(AuthorizationEndpoint, new NameValueCollection
{
{ "response_type", "code" },
{ "client_id", AppId },
{ "scope", "openid" },
{ "prompt", "select_account"},
{ "openid.realm", CloudServiceConfiguration.GetDNSName() },
{ "redirect_uri", returnUrl.GetLeftPart(UriPartial.Path) },
{ "state", state },
});
}
private static Uri BuildUri(string baseUri, NameValueCollection queryParameters)
{
var q = HttpUtility.ParseQueryString(string.Empty);
q.Add(queryParameters);
var builder = new UriBuilder(baseUri) { Query = q.ToString() };
return builder.Uri;
}
And here is what we use to generate the request to the token endpoint.
protected static Tuple<string, string> GetAuthTokens(Uri returnUrl, string authorizationCode)
{
var postData = HttpUtility.ParseQueryString(string.Empty);
postData.Add(new NameValueCollection
{
{ "grant_type", "authorization_code" },
{ "code", authorizationCode },
{ "client_id", AppId },
{ "client_secret", AppSecret },
{ "redirect_uri", returnUrl.GetLeftPart(UriPartial.Path) },
});
var webRequest = (HttpWebRequest)WebRequest.Create(TokenEndpoint);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
using (var s = webRequest.GetRequestStream())
using (var sw = new StreamWriter(s))
sw.Write(postData.ToString());
using (var webResponse = webRequest.GetResponse())
{
var responseStream = webResponse.GetResponseStream();
if (responseStream == null)
return null;
using (var reader = new StreamReader(responseStream))
{
var response = reader.ReadToEnd();
var json = JObject.Parse(response);
var accessToken = json.Value<string>("access_token");
var idToken = json.Value<string>("id_token");
return new Tuple<string,string>(accessToken,idToken);
}
}
}