How to connect to Google using OAuth2 and C# 53


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.
[wp_ad_camp_3]

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

[wp_ad_camp_3]
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.


About Linda Lawton

My name is Linda Lawton I have more than 20 years experience working as an application developer and a database expert. I have also been working with Google APIs since 2012 and I have been contributing to the Google .Net client library since 2013. In 2013 I became a a Google Developer Experts for Google Analytics.

Leave a Reply to Linda Lawton Cancel reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

53 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

    • 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.

    • 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

    • 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.

          • 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 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.

  • Piyush Kumar Dixit

    Hi Linda,

    I have a problem in Drive api integration in my asp.net mvc application. I wrote all the code and user are able to do all functionality related to google drive. But In my project all user can perform any operation without login because they don’t know my Userid or password. but right now they need my gmail uid and password before doing any operation.
    Below is my all code.

    I am waiting for your reply

    Thanks

    • Linda Lawton Post author

      If you are only going to be accessing the one account then you should be using a service account. Oauth2 is for gaining access to others accounts not a single one. This article may help you Google developer console service account

      If you have any issues i recommend posting your code on stack overflow that was to much code for this forum to support.

      If you need any assistance i have a consulting service you can contact me here

  • Shashwathi

    Hi,
    Thank you for the code, I am using this code to get the access token and using that access token I am trying to create a VIrtual Machine on google cloud. While creating Virtual Machine I have an Unauthorized exception(401)exception
    I am using c# language.
    Could you please help me to resolve this issue.
    Thank you