0

I am facing the same issue as mentioned in AuthenticationResult.IsSuccessful started returning false for google

I am using MVC 4 Web Api application and migrating it to MVC 5 would be a big change. Is somebody else facing the same issue ?

Are there any samples on how to use DotnetOpenAuth.OAuth2 so that I can skip migrating to DotnetOpenAuth.GoogleOAuth2 in a MVC 5 app.

Community
  • 1
  • 1
user2585299
  • 873
  • 2
  • 19
  • 41
  • Here you are, my answer to a similar question: http://stackoverflow.com/questions/21420019/dotnetopenauth-4-3-and-google-oauth-1-0-deprecated/21425099#21425099 – Wiktor Zychla Mar 24 '14 at 18:14
  • Do you think migrating to use Google+ Sign In would be a better option ? Have a look at https://developers.google.com/+/api/auth-migration#timetable – user2585299 Mar 24 '14 at 19:43
  • You don't have to. Just migrate to what they call "OAuth2 OpenID Connect" https://developers.google.com/+/api/auth-migration#oauth2login Basically they change endpoint addresses and they way you fetch user emails. – Wiktor Zychla Mar 24 '14 at 21:05
  • Thank you for your suggestions. We decided to go with Google+ Sign In though. Do you know if it can be used without integrating it with OAuth infrastructure provided by Microsoft as found here http://blog.beabigrockstar.com/google-signin-for-asp-net-mvc/ – user2585299 Mar 27 '14 at 23:46

1 Answers1

1

In case someone still need to use Google OpenID Connect in MVC 4 here is a code:

In AuthConfig.cs write:

OAuthWebSecurity.RegisterClient(new GoogleCustomClient("YoutGoogleAPIKey", "GoogleSecret"), "Google", null);

and the GoogleCustomClient class (based on a LinkedIn oAuth example I found):

using DotNetOpenAuth.AspNet;
using DotNetOpenAuth.AspNet.Clients;
using DotNetOpenAuth.OAuth;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Script.Serialization;


namespace MyProject.CustomProviders
{
public class GoogleCustomClient : OAuth2Client
{
    #region Constants and Fields
    private const string AuthorizationEndpoint = "https://accounts.google.com/o/oauth2/auth";
    private const string TokenEndpoint = "https://accounts.google.com/o/oauth2/token";
    private readonly string _clientId;
    private readonly string _clientSecret;
    private string absoluteReturnUrl = string.Empty;
    #endregion

    public GoogleCustomClient(string clientId, string clientSecret) : base("Google")
    {
        this._clientId = clientId;
        this._clientSecret = clientSecret;
    }

    protected override Uri GetServiceLoginUrl(Uri returnUrl)
    {
        StringBuilder serviceUrl = new StringBuilder();
        serviceUrl.AppendFormat("{0}?", AuthorizationEndpoint);
        serviceUrl.Append("response_type=code");
        serviceUrl.AppendFormat("&client_id={0}", this._clientId);
        serviceUrl.Append("&scope=email");
        absoluteReturnUrl = Regex.Match(returnUrl.ToString(), "https://(\\d|\\w|\\/|:|\\.){1,}").Value;
        serviceUrl.AppendFormat("&redirect_uri={0}", Uri.EscapeDataString(absoluteReturnUrl));
        serviceUrl.AppendFormat("&state={0}", Regex.Match(returnUrl.AbsoluteUri, "(?<=__sid__=).*?($|&)", RegexOptions.IgnoreCase).Value);
        return new Uri(serviceUrl.ToString());
    }

    protected override IDictionary<string, string> GetUserData(string accessToken)
    {
        var request = WebRequest.Create("https://www.googleapis.com/oauth2/v1/userinfo?access_token=" + Uri.EscapeDataString(accessToken));

        string responseText = string.Empty;
        using (var response = request.GetResponse())
        {
            using (var responseStream = response.GetResponseStream())
            {
                using (var reader = new StreamReader(responseStream, Encoding.UTF8))
                {
                    responseText = reader.ReadToEnd();
                }
            }
        }
        Dictionary<string, string> userData = new Dictionary<string, string>();
        JavaScriptSerializer deserializer = new JavaScriptSerializer();
        Dictionary<string, string> responseData = deserializer.Deserialize<Dictionary<string, string>>(responseText);
        userData.Add("id", responseData["id"]);
        userData.Add("firstname", responseData["given_name"]);
        userData.Add("lastname", responseData["family_name"]);
        userData.Add("emailAddress", responseData["email"]);
        userData.Add("picture", responseData["picture"]);
        userData.Add("accesstoken", "");
        userData.Add("allData", responseText);
        return userData;
    }

    protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
    {
        StringBuilder postData = new StringBuilder();
        postData.Append("grant_type=authorization_code");
        postData.AppendFormat("&code={0}", authorizationCode);
        postData.AppendFormat("&redirect_uri={0}", absoluteReturnUrl.EndsWith(returnUrl.ToString(), StringComparison.OrdinalIgnoreCase) ? HttpUtility.UrlEncode(absoluteReturnUrl) : "");
        postData.AppendFormat("&client_id={0}", this._clientId);
        postData.AppendFormat("&client_secret={0}", this._clientSecret);

        string response = "";
        string accessToken = "";

        var webRequest = (HttpWebRequest)WebRequest.Create(TokenEndpoint);

        webRequest.Method = "POST";
        webRequest.ContentType = "application/x-www-form-urlencoded";

        try
        {
            using (Stream s = webRequest.GetRequestStream())
            {
                using (StreamWriter sw = new StreamWriter(s))
                    sw.Write(postData.ToString());
            }
            using (WebResponse webResponse = webRequest.GetResponse())
            {
                using (StreamReader reader = new StreamReader(webResponse.GetResponseStream()))
                {
                    response = reader.ReadToEnd();
                }
            }

            JavaScriptSerializer deserializer = new JavaScriptSerializer();
            var userData = deserializer.Deserialize<Dictionary<string, string>>(response);
            accessToken = (string)userData["access_token"];
        }
        catch (Exception)
        {
            return null;
        }

        return accessToken;

    }

    public override AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl)
    {

        string code = context.Request.QueryString["code"];
        if (string.IsNullOrEmpty(code))
        {
            return AuthenticationResult.Failed;
        }

        string accessToken = this.QueryAccessToken(returnPageUrl, code);
        if (accessToken == null)
        {
            return AuthenticationResult.Failed;
        }

        IDictionary<string, string> userData = this.GetUserData(accessToken);
        if (userData == null)
        {
            return AuthenticationResult.Failed;
        }

        string email = userData["emailAddress"];
        string id = userData["id"];

        userData["accesstoken"] = accessToken;

        return new AuthenticationResult(isSuccessful: true, provider: this.ProviderName, providerUserId: id, userName: email, extraData: userData);
    }
}
}

And for some reason OAuthWebSecurity.VerifyAuthentication in the function "ExternalLoginCallback" is not going to the right class so here is a workaround:

AuthenticationResult result = ((GoogleCustomClient)OAuthWebSecurity.GetOAuthClientData("google").AuthenticationClient).VerifyAuthentication(this.HttpContext, uri);
RoyBS
  • 1,241
  • 16
  • 16