Monday, May 2, 2011

How to Integrate Google Authentication in Asp.Net Application

Hi here I am going to discuss how to integrate Google authentication in our local asp.net Application.
Recently I got the requirement to integrate Google authentication with asp.net application which is build using asp.net membership concept. My main aim is to use Google authentication in my application because now a days as everybody knows security is crucial for our applications. So I decided to use Google authentication in my application.
Google providing Authentication services for web application
As Google documented The OAuth authorization process involves a series of interactions between your web application, Google's authorization servers, and the end user.
At a basic level, the process is as follows:
  1. Your application requests access and gets an unauthorized request token from Google's authorization server.
  2. Google asks the user to grant you access to the required data.
  3. Your application gets an authorized request token from the authorization server.
  4. You exchange the authorized request token for an access token.
  5. You use the access token to request data from Google's service access servers.
When your application initially requests access to a user's data, Google issues an unauthorized request token to your application.
When user requests for local application URL http://localhost:50034/Login.aspx

If the user is not already logged in, Google prompts the user to log in page.

Google then displays an authorization page that allows the user to see what Google service data your application is requesting access to

If the user approves your application's access request, Google issues an authorized request token. Each request token is valid for only one hour. Only an authorized request token can be exchanged for an access token, and this exchange can be done only once per authorized request token.
By default, access tokens are long-lived. Each access token is specific to the user account specified in the original request for authorization, and grants access only to the services specified in that request. Your application should store the access token securely, because it's required for all access to a user's data.
We have mainly two methods to access Google authentication in to our application
1. Request for token
2. Handles the token
private string realm = null;
private string provider = "Google";
protected void Page_Load(object sender, EventArgs e)
        {
            realm = Request.Url.Scheme + "://" + Request.Url.DnsSafeHost + ":" + Request.Url.Port + Request.ApplicationPath;

            if (!IsPostBack)
            {
                if (!String.IsNullOrEmpty(Request.PathInfo))
                {
                    if (Request.PathInfo.StartsWith("/requestToken"))
                        MakeRequestForToken();
                    else if (Request.PathInfo.StartsWith("/authorizeToken"))
                        HandleAuthorizeTokenResponse();
                }
            }
        }

        /// <summary>
        /// Step 1: Get a Request Token
        /// </summary>
        private void MakeRequestForToken()
        {
            string consumerKey = "anonymous";
            string consumerSecret = "anonymous";
            // Google requires an additional "scope" parameter that identifies one of    the google applications
            string requestTokenEndpoint = "https://www.google.com/accounts/OAuthGetRequestToken?scope=https://www.googleapis.com/auth/userinfo#email";
            string requestTokenCallback = GetRouteableUrlFromRelativeUrl("GoogleAuth/oAuth/GoogleValidation.aspx/authorizeToken/google/");
            string authorizeTokenUrl = "https://www.google.com/accounts/OAuthAuthorizeToken";

            // Step 1: Make the call to request a token
            var oAuthConsumer = new OAuthConsumer();
            var requestToken = oAuthConsumer.GetOAuthRequestToken(requestTokenEndpoint,   realm, consumerKey, consumerSecret, requestTokenCallback);
            PersistRequestToken(requestToken);

            // Step 2: Make a the call to authorize the request token
            Response.Redirect(authorizeTokenUrl + "?oauth_token=" + requestToken.Token);
        }

        private void HandleAuthorizeTokenResponse()
        {
            string consumerKey = "anonymous";
            string consumerSecret = "anonymous";
            string token = Request.QueryString["oauth_token"];
            string verifier = Request.QueryString["oauth_verifier"];
            string accessTokenEndpoint = "https://www.google.com/accounts/OAuthGetAccessToken";

            // Exchange the Request Token for an Access Token
            var oAuthConsumer = new OAuthConsumer();

            var accessToken = oAuthConsumer.GetOAuthAccessToken(accessTokenEndpoint, realm, consumerKey, consumerSecret, token, verifier, GetRequesttoken().TokenSecret);

            // Google Only - This method will get the email of the authenticated user
            var responseText = oAuthConsumer.GetUserInfo("https://www.googleapis.com/userinfo/email", realm, consumerKey, consumerSecret, accessToken.Token, accessToken.TokenSecret);

            string queryString = responseText;
            NameValueCollection nvc = StringToNameValueCollection(responseText);

            if (nvc["email"] != "")
            {
                string userName = "";
                string password = "";
                userName = Membership.GetUserNameByEmail(nvc["email"].ToString());
                password = Membership.Provider.GetPassword(userName, String.Empty);
                FormsAuthentication.RedirectFromLoginPage(userName, false);
            }
        }

In above method I am getting Email of the authorised person by Google and I am checking with my database for email existence, if he is existed in my database i will give him permission to access my application.
Web.cofig file Settings
<configuration>
  <connectionStrings>
    <add name="Connection" connectionString="Data Source=RD780-RANDDMC;Integrated Security=true;Initial Catalog=Sample" providerName="System.Data.SqlClient"/>
  </connectionStrings>
  <system.web>
    <membership>
      <providers>
        <clear/>
        <add name="AspNetSqlMembershipProvider"
             type="System.Web.Security.SqlMembershipProvider"
             connectionStringName="Connection"
             applicationName="sampleapplication"
             enablePasswordRetrieval="true"
             enablePasswordReset="true"
             requiresQuestionAndAnswer="false"
             requiresUniqueEmail="true"
             passwordFormat="Encrypted"
             maxInvalidPasswordAttempts="5"
             minRequiredPasswordLength="4"
             minRequiredNonalphanumericCharacters="0"
             passwordAttemptWindow="10"
             passwordStrengthRegularExpression="^(?=.*\d).{4,8}$"
           />
      </providers>
    </membership>
    <authentication mode="Forms">
      <forms name=".ASPXFORMSDEMO" loginUrl="~/Login.aspx"/>
    </authentication>
    <authorization>
      <allow users = "*" />
      <deny users ="?" />
    </authorization>
    <profile>
      <providers>
        <clear/>
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="Connection" applicationName="SampleApplication"/>
      </providers>
    </profile>
    <roleManager enabled="false">
      <providers>
        <clear/>
        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="Connection" applicationName="SampleApplication"/>
      </providers>
    </roleManager>
    <machineKey validationKey= "836B8961579E88E2BE1819C1176518A6BECCD1670B783C62E8C4E16B2A5637EAFA0C743E8A0B81A6BF25A5539F2EE716948BFFD3B980FFF26533F8CAD71C9767"
decryptionKey="B3AFD7D4C4C1513E06403664B1DA7FEC7E0D225B23B3FD83DE99B9A75708352C" validation="SHA1" decryption="AES"/>
    <compilation debug="true" targetFramework="4.0"/>
  </system.web>
</configuration>

Here I am proving sample. Please download and try to use Google authentication in your asp.net application.
Note: when running this application you may get the following error while retrieving passwords from asp.net membership user.
You must specify a non-autogenerated machine key to store passwords in the encrypted format. Either specify a different passwordFormat, or change the machineKey configuration to use a non-autogenerated decryption key.
Please refer this link to resoleve the above issue
References

18 comments:

  1. i want to integrate this system within my asp.net site (i already installed the members api), how can i do it?

    ReplyDelete
  2. Hi you can directly copy all the classes which is in lib folder and you can do your stuff,please refer sample carefully which is provided.

    ReplyDelete
  3. I'm programming in VB.net so I translated your code to VB.net. I confess... I've used http://www.developerfusion.com/tools/convert/csharp-to-vb/

    GetRouteableUrlFromRelativeUrl, OAuthConsumer, PersistRequestToken, GetRequesttoken and StringToNameValueCollection instructions are not reconized.

    Which libraries should I import/use?

    Thanks.

    ReplyDelete
  4. Hi Nuno Barros
    GetRouteableUrlFromRelativeUrl, PersistRequestToken, GetRequesttoken and StringToNameValueCollection all are methods,which all are already provided in code,OAuthConsumer is a user defined class.Download Provided Code.

    ReplyDelete
  5. if (nvc["email"] != "")
    {
    string userName = "";
    string password = "";
    userName = Membership.GetUserNameByEmail(nvc["email"].ToString());
    password = Membership.Provider.GetPassword(userName, String.Empty);
    FormsAuthentication.RedirectFromLoginPage(userName, false);
    }

    Above code in GoogleValidation.cs checks the email against local database and then log's in the user using Google Authentication. I want to know if I can just bypass that step and have anyone with Google Account to login to my application!

    ReplyDelete
  6. Hi CAS,if you don't want to validate in the database you can skip this step,you can write simply as follows
    if (nvc["email"] != "")
    {
    Response.Reditect("page you wanted to redirect");
    }

    or
    you can use OpenId concept,which is available from google.

    ReplyDelete
  7. Hi ,I jus found one thing that when I get a google request access page and when i click on deny access, your sample doesnt handle the deny request. It is giving me exception. Can you please make a note of it.
    Regards,
    Nagesh...

    ReplyDelete
  8. Sure Nagesh,i will look into it,thanks for the note.

    ReplyDelete
  9. Hi, very good article! It somehow set more "scope" parameter? I tried it and still get "Bad request". I try to enter according to the documentation:
    string = requestTokenEndpoint and does not work.
    Can you please advise me why this does not work? Thanks.

    ReplyDelete
  10. Hi, good article. It somehow send multiple values ​​in the parameter scope (such as email and first and last name)?
    Thanks.

    ReplyDelete
  11. Hi Srinivas Ganaparthi
    you can tell me more about this?
    "you can use OpenId concept,which is available from google."
    thank!

    ReplyDelete
  12. where the values?
    it dynamically or Province?
    What is the significance?
    I do not understand this value?
    sorry I do not write good English

    ReplyDelete
  13. Hi Srinivas,
    Using this how I can extract Google/gMail contacts? Already I have written a piece of code which can extract contacts successfully from gmail when running on Gmail. But when uploading in server then gMail throwing suspecious attempt to login error.

    It will be very helpful I you can help me on this issue.

    Thanks
    Suman

    ReplyDelete
  14. How can Integrate Yahoo Mail On My ASP.NET Application..Please Help me..I searched lot of websites but I can't got it.

    ReplyDelete
  15. Very informative blog. Really looking forward to read more. Want more.
    integrated security systems

    ReplyDelete
  16. What about Oath2? This is a great example but needs to be updated.

    ReplyDelete
  17. Doesn't google api return any access token. In my application i want to access user's profile via an access token. Does Google provide this. if yes then how to extract that from response URL. Thanx in advance.

    ReplyDelete