How to connect to Google using OAuth2 and C# 36


Please Share

oauth-2-smAre you trying to connect to one of the Google APIs Using C#? Are you trying to do this in .net framework 3.5 – 2.0? In this post I will be showing you how to authenticate to Google API, as an example we will be email and google plus profile as example. If you can use .net framework 4.0 or 4.5 I strongly recommend that you use the Google .net client library using the client library is much easier. This is doing it the hard way in my opinion. I have a sample project on GitHub to go along with this tutorial feel free to download it to follow along GoogleAuthSimple

There are several reasons why I’m not going to use the dlls.

  1. To understand how Open Authentication works it helps to see the Pure code. See how it works instead of relying on a third party dll.
  2. If you are planing on referencing Google’s open Auth dll into your own dll it wont work because inst currently strong named.   (They should be soon)
  3. I personally like to limit the number of 3rd party dll’s I use in my projects.

Creating the Form

Lets get started.  I am going to assume here that you have created a project in Google APIs console if you haven’t I have a previous post you can read on how to do it: Googles APIs Console

The first thing we need to do is create a windows form application.  Create two forms one with a button on it and one with a web-browser control.

AuthResponse

AuthResponse is a class I have created that contains all the methods we need to authenticate. You should copy it now the rest of the tutorial will be using methods directly from it.

using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using System.Net;
using System.IO;

namespace GoogleAuthWinForm
{
    public class AuthResponse
    {
        private string access_token;
        public string Access_token
        {
            get
            {            
                // Access token lasts an hour if its expired we get a new one.
                if (DateTime.Now.Subtract(created).Hours > 1)
                {
                    refresh();
                }
                return access_token;
            }
            set { access_token = value; }
        }
        public string refresh_token { get; set; }
        public string clientId { get; set; }
        public string secret { get; set; }
        public string expires_in { get; set; }
        public DateTime created { get; set; }
        

        /// 
        /// Parse the json response 
        /// //  "{\n  \"access_token\" : \"ya29.kwFUj-la2lATSkrqFlJXBqQjCIZiTg51GYpKt8Me8AJO5JWf0Sx6-0ZWmTpxJjrBrxNS_JzVw969LA\",\n  \"token_type\" : \"Bearer\",\n  \"expires_in\" : 3600,\n  \"refresh_token\" : \"1/ejoPJIyBAhPHRXQ7pHLxJX2VfDBRz29hqS_i5DuC1cQ\"\n}"
        /// 
        /// 
        /// 
        public static AuthResponse get(string response)
        {
            AuthResponse result = JsonConvert.DeserializeObject(response);
            result.created = DateTime.Now;   // DateTime.Now.Add(new TimeSpan(-2, 0, 0)); //For testing force refresh.
            return result;
        }


        public void refresh()
        {
            var request = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");
            string postData = string.Format("client_id={0}&client_secret={1}&refresh_token={2}&grant_type=refresh_token", this.clientId, this.secret, this.refresh_token);
            var data = Encoding.ASCII.GetBytes(postData);

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }

            var response = (HttpWebResponse)request.GetResponse();
            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
            var refreshResponse = AuthResponse.get(responseString);
            this.access_token = refreshResponse.access_token;
            this.created = DateTime.Now;
        }


        public static AuthResponse Exchange(string authCode, string clientid, string secret, string redirectURI)
        {

            var request = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");

            string postData = string.Format("code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type=authorization_code", authCode, clientid, secret, redirectURI);
            var data = Encoding.ASCII.GetBytes(postData);

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }

            var response = (HttpWebResponse)request.GetResponse();

            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

            var x = AuthResponse.get(responseString);

            x.clientId = clientid;
            x.secret = secret;

            return x;

        }



        public static Uri GetAutenticationURI(string clientId, string redirectUri)
        {
            string scopes = "https://www.googleapis.com/auth/plus.login email";

            if (string.IsNullOrEmpty(redirectUri))
            {
                redirectUri = "urn:ietf:wg:oauth:2.0:oob";
            }
            string oauth = string.Format("https://accounts.google.com/o/oauth2/auth?client_id={0}&redirect_uri={1}&scope={2}&response_type=code", clientId, redirectUri, scopes);
            return new Uri(oauth);
        }

    }
}

Add this class to visual studio will allow you to run the rest of the tutorial.


Request user access.

In order for this to work you need to have first register your application in Googles APIs Console.  Under API Access you should have something like this.

clientid

In order to display the Authentication request to the user you must first have the Uri to put into your web browser control. note &response_type=code

public static Uri GetAutenticationURI(string clientId, string redirectUri)
  {
  // separate more then one scope with a space
  string scopes = "https://www.googleapis.com/auth/plus.login email";   
  if (string.IsNullOrEmpty(redirectUri))
   {
   redirectUri = "urn:ietf:wg:oauth:2.0:oob";
   }
 string oauth = string.Format("https://accounts.google.com/o/oauth2/auth?client_id={0}&redirect_uri={1}&scope={2}&response_type=code", clientId, redirectUri, scopes);
return new Uri(oauth);
  }

This first request is just a simple HTTP GET. A HTTP GET requests a representation of the specified resource. Requests using GET should only retrieve data and should have no other effect. With Visual Stuido C# and as far back as .net 2.0 we can also do HTTP GET just by using System.Net.

  1. {ClientID} – This is the Id that identifies your application to Google. Its the id that was created for you in the Google Apis Console.
  2. {Redirect URI} – This tells the server where to send the authorization code to.  Put urn:ietf:wg:oauth:2.0:oob there and it will redirect to the current browser window and its title.
  3. {Scope} –  This is what API you are requesting access to.  When you registered your project you checked off which API’s you will be using in the services tab.  Each API has one or more Scope.   For Google+ its https://www.googleapis.com/auth/plus.login and for email its just “email”  you can add more then one by separating them with a space.    Check the API you will be using to find out which Scope you  need to access the data you are looking for.
  4. Response_type=code  –  This just tells them you want an authorization code back.

If you debug the code you will see that oauth now looks like this :

https://accounts.google.com/o/oauth2/auth?client_id=XXXX-d0vpdthl4ms0soutcrpe036ckqn7rfpn.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/plus.login email&response_type=code"

You can place that string into any web browser and it will work.

I like to call the method like this

 webBrowser1.Navigate(AuthResponse.GetAutenticationURI(clientId, redirectURI)); 

When the web browser:.

Authentication

Now we are asking the User if they want to give you access to there data.  Lets assume they clicked “Accept”.

There are three types of codes you need to be aware of with Open Autentication.

  1. Authentication code –  This is the code that is returned to you when the user gives you access. You only need this once its used to get a refreshtoken.
  2. Refresh token –   This is the only thing you need to remember for next time.   You need to save this in your application so that when the user starts your program again they wont need to re-Authenticate.  With a refresh token you can request a new access token.
  3. Access token –  This is the main token you need.   When ever you send a request you must send this along with the request.   Access tokens have a life of about an hour so you need to check if its expired or not.  By checking the Expire time.   We will look into that later.

Finding the Authentication Code



The Authentication code is returned to us in Visual Studio web-browser control in both in the body of the page when it reloads as well as in the title.    I recommend that you read it from the body.  I have had some issues with not getting the complete code out of the title.  I don’t know if it was because it was to long or if its because the code has special characters in it.   I just know on a several occasions I have had issues with it so I always read from the body.

 
 /// 
 /// The authentication code is returned in the webbrowser.
 /// 
 /// 
 /// 
 private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
 {
      string Mytitle = ((WebBrowser)sender).DocumentTitle.ToLower();
      if (Mytitle.IndexOf("success code=") > -1)
       {
         webBrowser1.Visible = false;

      // searching the body for our code
       string AuthCode = webBrowser1.DocumentTitle.Replace("Success code=", "");
       string webText = ((WebBrowser)sender).DocumentText;
     int start = webText.IndexOf("id=\"code\"");
     start = webText.IndexOf(AuthCode, start);
     int end = webText.IndexOf('"', start);
     string authCode = webText.Substring(start, end - start);

     //Exchange the code for Access token and refreshtoken.
    access = AuthResponse.Exchange(authCode, clientId, clientSecret, redirectURI);

    processAccess();
    }
}

I am sure some C# guru can come up with a nice Regex match to find the code for us. I use this because its simple and it works and it doesn’t require that I include regex into my project. AuthCode now contains the authentication code, we will use the authentication code to get a refresh token.

Exchanging the Authentication Code

Now we have an Authentication code but what we need is an Access token and a refresh token. This time we will be doing a HTTP POST, a HTTP Post can also be done with visual studio as far back as .net framework 2.0. What we want to do is send some information to the server this time.

The authentication code, the client id , the client secret and the redirect uri. note grant_type=authorization_code

Once we have done this the server will return to us an Access token which we can use to make requests against the api and a refresh token. Access tokens are only good for about an hour so we will we need to get a new one we use the refresh token to get a new access token.

 public static AuthResponse Exchange(string authCode, string clientid, string secret, string redirectURI)
        {

        var request = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");

       string postData = string.Format("code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type=authorization_code", authCode, clientid, secret, redirectURI);
       var data = Encoding.ASCII.GetBytes(postData);

       request.Method = "POST";
       request.ContentType = "application/x-www-form-urlencoded";
       request.ContentLength = data.Length;

       using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }

      var response = (HttpWebResponse)request.GetResponse();

      var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

      var x = AuthResponse.get(responseString);

      x.clientId = clientid;
      x.secret = secret;

      return x;

}

You should now have an access token and a refresh token that you can use for all future request against the Google APIs.

Using the refresh token

When your Access token has expired you need to request a new one.  For that you use the refreshToken. Note grant_type=refresh_token

 public void refresh()
        {
            var request = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");
            string postData = string.Format("client_id={0}&client_secret={1}&refresh_token={2}&grant_type=refresh_token", this.clientId, this.secret, this.refresh_token);
            var data = Encoding.ASCII.GetBytes(postData);

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }

            var response = (HttpWebResponse)request.GetResponse();
            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
            var refreshResponse = AuthResponse.get(responseString);
            this.access_token = refreshResponse.access_token;
            this.created = DateTime.Now;
        }

Conclusion

As you can see it is possible to gain access to Google APIs without using the client library. Its not really that hard you just have to know what calls to make. Once you have the access token you can then make any request against the API you wish by simply adding the key to the end of the request url. I have uploaded a sample project for this to GitHub that should get you started.

Please Share


Linda Lawton

About Linda Lawton

My name is Linda Lawton I have more than 20 years experience working as a developer and a database expert. I have been working with several of the Google APIs, since 2012. I helping others in the On-Line community to develop with the Google APIs, by creating my own blog www.daimto.com. This and my presence on a number of On-Line developer forums lead me to be noticed by the Google Analytics API development team. I was nominated for and recently became one of the first Google Developer Experts for Google Analytics.


Leave a comment

Your email address will not be published. Required fields are marked *

36 thoughts on “How to connect to Google using OAuth2 and C#

  • Alanga Kumar

    Hello

    Thanks for the codes, that can be used to authorize for any Google service.
    But how can we instantiate a Google Drive Service, client using above approach.

    Thanks
    Please reply soon.

  • Shyams

    hi
    I am looking sample code that help me to extract google Task item using email address and create task. I could not find any tutorial and sample code. i used to google Task API but able to create task

    • Administrator
      Linda Lawton

      I don’t have any tutorials yet for Google Task API but i don’t think you are going to get it to work with an email address. You need to use Oauth2, Google doesn’t like client login anymore.

  • Faraz Azhar

    Hello. Very good explanation on how to connect Google using OAuth. Although Google itself provides an OAuth API, which does the same thing. But I prefer the method you explained here because I want to be in control of the web browser window. Google OAuth Api uses the default web browser on the computer. I’ve had trouble catching situations where user closes the browser window instead of accepting or rejecting userconsent. That’s why with my own webbrowser I am able to catch this.
    Now next step is to inject the access token in the DriveService for using Google Drive SDK. The most familiar code is this:
    drvservice = New DriveService(New BaseClientService.Initializer() With {.HttpClientInitializer = credential, .ApplicationName = “app”})
    How do I use the access token received from your article and apply it on the DriveService so I can access the user’s Drive account.

    • Administrator
      Linda Lawton

      What you are talking about would be merging non client lib code with client lib code. If your not going to use Googles Client lib to create the Oauth code then i think you are going to have problems using the client lib. I will look into it you might be able to create the credential object manually in the client lib but I’m not sure.

  • Tom

    Could you share a SampleProject for everybody , because i’m a beginner for Google API , i don’t know how to use those introduction to create a usable WinForms Application even i try it that i failed , so if you can share example for me , i should be glad for your sharing.

  • m0nsieur Gazper

    Where the POST function come from?

    //Posting the Data to Google
    string response = Post(“https://accounts.google.com/o/oauth2/token”, postData);

  • m0nsieur Gazper

    In the code:
    //Posting the Data to Google
    string response = Post(Properties.Resource.TokenEndpoint, postData);
    Where Properties come from?

  • João Lucas Farias

    Hello, Linda. Congratulations for your code and website, it’s literally saving my life! Hahaha
    Well, I have a question about your code. What does that line means:
    GoogleAnalyticsWin.MainForm._MainUIForm.SetAutentication(myAutentication);
    ?
    That’s not working in my application
    What am I doing wrong?
    Please help me!

  • Pnc

    string response = Post(Properties.Resource.TokenEndpoint, postData);
    Getting Error in this line..What is Properties.Resource.TokenEndpoin means
    plz reply

    • Administrator
      Linda Lawton

      This tutorial is really old. I am really not that sure, I will add it to my list of Clean up tutorials. If you can’t use the Google .net client lib feel free to email me and i will see if i cant find the source code for this tutorial someplace.

  • Hiren

    i am uploading the youtube video in .net using oauth 2.0 but while deploying into IIS its not able to authenticate. is there any specific configuration is required while deploying the application.

      • Hiren

        Thanks for your reply.

        i am using the below code for the authentication.

        var stream = new FileStream(clientSecretFilePath, FileMode.Open, FileAccess.Read);
        {
        if (scope == YouTubeScope.ReadOnly)
        {
        credentials = await GoogleWebAuthorizationBroker.AuthorizeAsync(
        GoogleClientSecrets.Load(stream).Secrets,
        new[] { YouTubeService.Scope.YoutubeReadonly },
        “user”,
        CancellationToken.None,
        new FileDataStore(Assembly.GetExecutingAssembly().GetName().Name)
        );
        }
        else
        {
        credentials = await GoogleWebAuthorizationBroker.AuthorizeAsync(
        GoogleClientSecrets.Load(stream).Secrets,
        new[] { YouTubeService.Scope.YoutubeUpload },
        “user”,
        CancellationToken.None
        );
        }

        After running this code its not able to authorized to the Google from IIS. Is there any other way to use this authentication or any configuration we can do in IIS. Same code if i am running using Visual Studio its working properly.
        i have given same window credential in IIS App pool. Is there any other changes are required or do I need to change the code?

          • Hiren

            IIS has access of clientSecretFilePath. i found while remote debugging that it hangs over at the below mehod.

            await GoogleWebAuthorizationBroker.AuthorizeAsync(
            GoogleClientSecrets.Load(stream).Secrets,
            new[] { YouTubeService.Scope.YoutubeReadonly },
            “user”,
            CancellationToken.None,
            new FileDataStore(Assembly.GetExecutingAssembly().GetName().Name)
            );

          • Hiren

            But the same code works if its running from the code in visual studio. once i deploy in IIS then only its not working.

          • Administrator
            Linda Lawton

            Never mind that. This isn’t the best place to do debugging of code. You should post your question to http://stackoverflow.com/ tag it google-api-dotnet-client and youtube-api. Comments on this site just doesn’t work for asking questions not related to the tutorial in question.

  • Hiren

    i am using the below code for the authentication.

    var stream = new FileStream(clientSecretFilePath, FileMode.Open, FileAccess.Read);
    {
    if (scope == YouTubeScope.ReadOnly)
    {
    credentials = await GoogleWebAuthorizationBroker.AuthorizeAsync(
    GoogleClientSecrets.Load(stream).Secrets,
    new[] { YouTubeService.Scope.YoutubeReadonly },
    “user”,
    CancellationToken.None,
    new FileDataStore(Assembly.GetExecutingAssembly().GetName().Name)
    );
    }
    else
    {
    credentials = await GoogleWebAuthorizationBroker.AuthorizeAsync(
    GoogleClientSecrets.Load(stream).Secrets,
    new[] { YouTubeService.Scope.YoutubeUpload },
    “user”,
    CancellationToken.None
    );
    }

    After running this code its not able to authorized to the Google from IIS. Is there any other way to use this authentication or any configuration we can do in IIS. Same code if i am running using Visual Studio its working properly.
    i have given same window credential in IIS App pool. Is there any other changes are required or do I need to change the code?

  • Armugam

    Hi Linda,

    I have a doubt regarding the above sample code given by you.

    1) Where we have to declare this “myAutentication” variable?

    2) In “wbAuthenticate_DocumentCompleted” function

    if (myAutentication.ErrorMessage.Length > 0)

    what is “&gt” meant for ?

    3) And in the same method
    else if (Mytitle.IndexOf(“denied error=”) > -1)
    {
    // the user declined access. Show them the URL again
    wbAuthenticate.Url = GetAutenticationURI(myAutentication);
    }
    Where is this “GetAutenticationURI” located in?

    Please provide me the sample project for web browser control,windows App using c# if possible …

    Thank You for your Guidance… 🙂

      • pankaj

        Hi Linda, i am using code provided by youtube api v3 to upload video. this is my code to get authentication

        UserCredential credential;
        using (var stream = new FileStream(jsonFileName, FileMode.Open, FileAccess.Read))
        {
        credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
        GoogleClientSecrets.Load(stream).Secrets, new[] { YouTubeService.Scope.YoutubeUpload },
        “user”,
        CancellationToken.None
        );
        }

        This is work well when i use visual studio, but when i host this on IIS i am getting error ”access to the path ‘google.apis.auth’ is denied”
        i am not able to fix this error, i have set all the permission to folder.

  • Trung Van Hoang

    Really Useful, i’m trying to access Google APi using my own Embed Webbrowser, but i need to access Youtube API. Can you help me get “Uri GetAutenticationURI(string clientId, string redirectUri)” for Youtube API

  • Amrut S Anegundi

    Hi Linda,

    I found this very useful because I don’t need to worry about browser close event. But I was wondering how can I further continue to download/upload files from Google Drive. Because all the examples I have seen over the internet is based on DriveService and as pointed out I should not be using the same. Can you help me out with a function/example that further uses the access token to upload a file in google drive. It will be very helpful. Thanks Again.

    Regards,
    Amrut

  • TingSpain

    Hello Linda,

    First of all, thank you for your article. Very great work. Thank you very much!
    I download your example at Github, however I am getting an error. I dont know why after I approve the authentication at the Auth Form, I get an error at line ” int end = webText.IndexOf(‘”‘, start); ” within the method webBrowser1_DocumentCompleted(). It seems that start has a value -1. It get the value -1 at “start = webText.IndexOf(AuthCode, start);” Before, start has another value. Has google changed the format of the authorization code? I dont know if the format (“id=\”code\””) is not working anymore.

    Any idea?

    Thank you very much in advance

    • Linda Lawton
      Linda Lawton Post author

      Yes that code is really old they may have changed it. I changed my application a while ago to read from document.title I think. There was also something about it doing a double load if i remember you need to be sure that the document complete was the correct one. Its been a while i will have to dig around in some code.