Skip to main content

Implementing Oauth2.0 authorization for Google in asp.net

Download Source Code

Introduction

Now a days, security is a major concern for every service provider like Google, Yahoo, Microsoft etc. and that’s why every service provider which is providing some external service to another app is following the protocol defined by Oauth.

I am going to describe here, how to implement google oauth in asp.net app.

Prerequisites

You should have basic knowledge of
  • C#
  • Asp.net

Steps for implementing

For implementing Oauth we will have to follow series of steps –
  • Create a project on google console.
  • Get the client id and client secret from the project.
  • Writing code for authorizing the user by google.
  • Writing code for exchanging the authorization code for refresh token.
  • Writing code for exchanging refresh token for access token.
Don’t worry about the above steps- i am going to explain these in details with demo.

Let’s Start

1.Create a Project on Google console

Goto https://console.developers.google.com and click on project -> new project



after that, a dialog box will appear.Write your project name and click on create.



now you have successfuly created a project.

2. Getting client id and client secret

Follow the steps as shown in screenshot –

1.Click on credential



2.Click on down arrow button near the create credential button.Clicking the down arrow button will open a drop down box ,from the drop down box click on Oauth client ID.



3.Click on Configure Consent Screen



4.Fill all the details and click on save



5. Again you will be redirected to credential screen.Click on Web Application and name your web app and click on Create button.For the time being ignore the other text box, i will explain those later in this article.
 

6. You will get your client id and client secret in a pop up. Copy the client id and client secret and keep it somewhere safe (Dont worry if you lost this code,you can get this code later from developer console).

3.Writing code for authorizing the user by google

1. Let’s create an asp.net project –



I am creating a web form project, but you can create any asp.net project like asp.net mvc or any other.
 
2. Add a web form inside the project with name – GoogleCallBack. This will be used as redirect url. Don’t worry, you will understand it later.





3.Add a web form inside the project with name -Authorize and paste the following html code inside the form –

<form id="form1" runat="server" method="get">  
    <div>  
        Enter User Id:  
        <input type="text" name="UserId">  
    </div>  
    <p>  
        <button type="submit">Submit</button>  
    </p>  
</form>


i am creating a page, where i will send the user id to the server.The server will determine, whether the user is authorized or not and if not authorized it will authorized the user. 4. Put the client id and client secret in web.config under “appSettings”, so that you can change this value later and it can be globally available for any page -



5. Remember , we have left some setup of project on google developer console.Its time to complete, otherwise google will decline the authorization. So perform the following steps in serial order-
  • Run the project

  • Open the Google developer console
  • Go to credential
  • Click on edit Oauth client

  • Now copy project url and paste in textbox of authorized javascript origin and keep it open.
  • Open the googlecallback.aspx in browser and copy the url.
  • Paste the url in authorized redirect uri.

now, we have completed settings of project on google developer console.Its time to get back to our implementation part .

6. Create a database with any name and inside the database - create the table having below design or you can also paste the below code in order to create the table.

create table Member  
(  
   UserId int primary key,  
   RefreshToken varchar(200),  
   GmailId varchar(200)  
)




7.Add connection string in web.config .Sorry, I am not going to this describe this.I assume you know how to do this one. 8.it’s time to write code for authorizing user – For Authorizing the user by google, you will have to redirect the user to google authorizing url with following query string –
  • client_id – you will have to pass the client id that you got from google console by creating an project.
  • redirect_uri – you will have to pass an absolute url. Google will redirect the user to this url after authorization with some value as ‘code’ or ‘error’ if any error occurred.
  • access_type – this will be used by google to know what type of access you want.There are two values – ‘online’ or ‘offline’.Default value is ‘online’,but we set it as ‘offline’, because we want the user authenticate one time and use the service again and again.
  • state – you can set any value.The same value will be returned by google after authorization. This is used to know the user details or any other things.You will understand this later.
  • login_hint- this value will be automatically filled by google in email text box.
  • scope – this value will be used by google to know what type of service an app is requesting for the user. e.g – gmail, calendar, google or user info etc. you can pass multiple values separated by space.
so, lets write the code for authorizing user – Copy the below code in authorize.aspx.cs under partial class -

protected void Page_Load(object sender, EventArgs e)  
{  
      //Get the user id from query string
    string UserId = Request.QueryString["UserId"]; 

    if (UserId != null)   //check whether user is null or not
    {  
        if (IsAuthorized(UserId))  //check whether user is already authorized
        {  
            string EmailId = GetGmailId(UserId);  //Get the email id from database

            //show the email id in alert
            ClientScript.RegisterClientScriptBlock(this.GetType(), "alert", "alert('" + EmailId + "')", true);   
        }  
        else  
        {  
            AuthorizeUser(UserId);  //authorize the user
        }  
    }  
  
}  
  
///   
/// Return gmail id from database. it will saved in the database after successful authentication.  
///   
///   
///   
private string GetGmailId(string userId)  
{  
    SqlConnection Con = new SqlConnection(ConfigurationManager.ConnectionStrings["DbConnection"].ConnectionString);  
    string Query = "select GmailId from Member where UserId=" + userId;  
    SqlCommand Cmd = new SqlCommand(Query, Con);  
    Con.Open();  
    string Result = Cmd.ExecuteScalar().ToString();  
    Con.Close();  
    return Result;  
}  
  
private bool IsAuthorized(string userId)  
{  
    SqlConnection Con = new SqlConnection(ConfigurationManager.ConnectionStrings["DbConnection"].ConnectionString);  
    string Query = "select count(*) from Member where UserId=" + userId;  
    SqlCommand Cmd = new SqlCommand(Query, Con);  
    Con.Open();  
    int Result = (int)Cmd.ExecuteScalar();  
    Con.Close();  
    return Result > 0 ? true : false;  
}  
  
private void AuthorizeUser(string data)  
{  
    string Url = GetAuthorizationUrl(data);  
    HttpContext.Current.Response.Redirect(Url, false);  
}  
  
///   
///   
///   
///   
///   
private string GetAuthorizationUrl(string data)  
{  
    string ClientId = ConfigurationManager.AppSettings["ClientId"];  
    string Scopes = "https://www.googleapis.com/auth/userinfo.email";  
  
    //get this value by opening your web app in browser.  
    string RedirectUrl = "http://localhost:52403/GoogleCallBack.aspx";  
  
    string Url = "https://accounts.google.com/o/oauth2/auth?";  
    StringBuilder UrlBuilder = new StringBuilder(Url);  
    UrlBuilder.Append("client_id=" + ClientId);  
    UrlBuilder.Append("&redirect_uri=" + RedirectUrl);  
    UrlBuilder.Append("&response_type=" + "code");  
    UrlBuilder.Append("&scope=" + Scopes);  
  
    UrlBuilder.Append("&access_type=" + "offline");  
    UrlBuilder.Append("&state=" + data);  //setting the user id in state
    return UrlBuilder.ToString();  
}

So, what the above code is doing -
  • When the page will load it will retrieve the user id from query string.
  • if we found the user id from query string, it will check whether user is already authorized or not.
  • if user is already authorized, then we will fetch the email from database and show it to the user.
  • if user is not authorised, we will authorise the user by following steps -
    • we will create an authorization url - this includes creating query string with client id,scope and all other things that i mentioned earlier.
    • we will redirect the user to the created url.
Now we have web page which will authorize the user. Let’s create the page for Saving the data in database after successful authorization. so we will have to write code in GoogleCallBack.aspx.cs

4.Writing code for exchanging the authorization code

After successful authorization, Google will call this page with an authorization code which is temporary – that means it will expire after few hour ,probably an hour. But we want the user to authenticate one time and use the service again and again.So what to do? By using authorization code, we can get refresh token which is valid for lifetime but it is not used for getting any service.So again the question will be, then what is the meaning of refresh token ?. By using refresh token, we can get access token which is used for getting service and again access token is temporary. So every time you want to use any service, you will have to get access token. i think now you understand the whole flow.So basically we will have to perform following steps-
  • Get the authorization code.
  • Exchange the authorization code for refresh token.
  • save the refresh token in database.
  • Exchange refresh token for access token.
  • Use access token for getting any service.
so, let’s write the code – Copy the below code in GoogleCallBack.aspx.cs under namespace -

public partial class GoogleCallBack : System.Web.UI.Page  
{  
  
    protected void Page_Load(object sender, EventArgs e)  
    {  
        //you will get this, when any error will occur while authorization otherwise null  
        string Error = Request.QueryString["error"];  
  
        //authorization code after successful authorization  
        string Code = Request.QueryString["code"];  
  
        if (Error != null)  
        {  
  
        }  
        else if (Code != null)  
        {  
  
  
            //Remember, we have set userid in State  
            string UserId = Request.QueryString["state"];  
  
            //Get AccessToken  
            int Id = Convert.ToInt32(UserId);  
  
            string AccessToken = string.Empty;  
            string RefreshToken = ExchangeAuthorizationCode(Id, Code, out AccessToken);  
  
            //saving refresh token in database  
            SaveRefreshToken(Id, RefreshToken);  
  
  
            //Get Email Id of the authorized user  
            string EmailId = FetchEmailId(AccessToken);  
  
            //Saving Email Id  
            SaveEmailId(UserId, EmailId);  
  
            //Redirect the user to Authorize.aspx with user id  
            string Url = "Authorize.aspx?UserId=" + UserId;  
            Response.Redirect(Url, true);  
  
        }  
    }  
  
    private string ExchangeAuthorizationCode(int userId, string code, out string accessToken)  
    {  
        accessToken = string.Empty;  
  
        string ClientSecret = ConfigurationManager.AppSettings["ClientSecret"];  
        string ClientId = ConfigurationManager.AppSettings["ClientId"];  
  
        //get this value by opening your web app in browser.  
        string RedirectUrl = "http://localhost:52403/GoogleCallBack.aspx";  
  
        var Content = "code=" + code +  
            "&client_id=" + ClientId +  
            "&client_secret=" + ClientSecret +  
            "&redirect_uri=" + RedirectUrl +  
            "&grant_type=authorization_code";  
  
        var request = WebRequest.Create("https://accounts.google.com/o/oauth2/token");  
        request.Method = "POST";  
        byte[] byteArray = Encoding.UTF8.GetBytes(Content);  
        request.ContentType = "application/x-www-form-urlencoded";  
        request.ContentLength = byteArray.Length;  
  
        using (Stream dataStream = request.GetRequestStream())  
        {  
            dataStream.Write(byteArray, 0, byteArray.Length);  
            dataStream.Close();  
        }  
  
        var Response = (HttpWebResponse)request.GetResponse();  
        Stream responseDataStream = Response.GetResponseStream();  
        StreamReader reader = new StreamReader(responseDataStream);  
        string ResponseData = reader.ReadToEnd();  
        reader.Close();  
        responseDataStream.Close();  
        Response.Close();  
        if (Response.StatusCode == HttpStatusCode.OK)  
        {  
            var ReturnedToken = JsonConvert.DeserializeObject(ResponseData);  
  
            if (ReturnedToken.refresh_token != null)  
            {  
                accessToken = ReturnedToken.access_token;  
                return ReturnedToken.refresh_token;  
            }  
            else  
            {  
                return null;  
            }  
        }  
        else  
        {  
            return string.Empty;  
        }  
    }  
  
    private void SaveRefreshToken(int userId, string refreshToken)  
    {  
        SqlConnection Con = new SqlConnection(ConfigurationManager.ConnectionStrings["DbConnection"].ConnectionString);  
        string Query = "insert into Member (UserId,RefreshToken) values(" + userId + ",'" + refreshToken + "')";  
        SqlCommand Cmd = new SqlCommand(Query, Con);  
        Con.Open();  
        int Result = Cmd.ExecuteNonQuery();  
        Con.Close();  
    }  
  
    private string FetchEmailId(string accessToken)  
    {  
        var EmailRequest = "https://www.googleapis.com/userinfo/email?alt=json&access_token=" + accessToken;  
        // Create a request for the URL.  
        var Request = WebRequest.Create(EmailRequest);  
        // Get the response.  
        var Response = (HttpWebResponse)Request.GetResponse();  
        // Get the stream containing content returned by the server.  
        var DataStream = Response.GetResponseStream();  
        // Open the stream using a StreamReader for easy access.  
        var Reader = new StreamReader(DataStream);  
        // Read the content.  
        var JsonString = Reader.ReadToEnd();  
        // Cleanup the streams and the response.  
        Reader.Close();  
        DataStream.Close();  
        Response.Close();  
  
        dynamic json = JValue.Parse(JsonString);  
        return json.data.email;  
    }  
  
    private bool SaveEmailId(string userId, string emailId)  
    {  
        SqlConnection Con = new SqlConnection(ConfigurationManager.ConnectionStrings["DbConnection"].ConnectionString);  
        string Query = "update Member set GmailId='" + emailId + "'where UserId='" + userId + "'";  
        SqlCommand Cmd = new SqlCommand(Query, Con);  
        Con.Open();  
        int Result = Cmd.ExecuteNonQuery();  
        Con.Close();  
        return Result > 0 ? true : false;  
    }  
  
  
  
}  
  
public class Token  
{  
    public string access_token { get; set; }  
    public string token_type { get; set; }  
    public string expires_in { get; set; }  
    public string refresh_token { get; set; }  
}  


What the above code is doing -
  • We have two things that will be returned by google either error or code.so we will check first if error is not null.if error is null, that means some error has occured while authorizing.
  • If error is null then we will check for code and if code is not null that means we have a token and user is authorized successfully. Now, we have got the temporary token, so we will have to use it to get the refresh token.we will call the exchange "authorizationcode" which will exchange the authorization code and will return refreshtoken and access token.(At the time of exchanging authorization code, the google also return access token, so we should use this access token instead of another http call to get the access token.)
  • Save the refresh token in database.
  • Get the email id using access token.
  • Save the email id in database.
  • Redirect the user to authorize.aspx with query string user id and now the user is authorized so we will get an alert with the user gmail id.
now, we have completed the coding part successfully.It’s time to rock.

Testing Implementation

Perform the following steps –
  • Run the project
  • Navigate to Authorize.aspx
  • Enter any user id which should be number
  • Click on Submit – If the user will be present inside the db then you will get the email id of the user in alert box, otherwise the user will be redirected to google authrization site.
  • An allow screen will appear, where user can see – what type of access, he/she is giving access to the app.Click on allow button. After clicking on allow button, the refresh token and gmail id will be saved to your DB and the user will be redirected to the authorize page.

Cool, Isn’t It?

Now, we have refresh token so the next question will be how to use the refresh token to get the access token?

5. Writing code for exchanging refresh token

Let’s create a web form with name GetEmail. It will be same like Authorize.aspx but instead of getting the email from database, we will fetch the email from Google using access token. So copy the html code from Authorize.aspx.
Now inside the GetEmail.aspx.cs copy the below code under partial class –
protected void Page_Load(object sender, EventArgs e)  
{  
    string UserId = Request.QueryString["UserId"];  
    if (UserId != null)  
    {  
        string RefreshToken = string.Empty;  
        if (IsAuthorized(UserId, out RefreshToken))  
        {  
            //Get Access token using Refresh token  
            string AccessToken = GetAccessToken(RefreshToken);  
  
            //Get Gmail Id  using access token  
            string EmailId = GetGmailId(AccessToken);  
  
            ClientScript.RegisterClientScriptBlock(this.GetType(), "alert", "alert('" + EmailId + "')", true);  
        }  
        else  
        {  
            string ErrorMsg = "You are not authorized";  
            ClientScript.RegisterClientScriptBlock(this.GetType(), "alert", "alert('" + ErrorMsg + "')", true);  
        }  
    }  
}  
  
  
  
private bool IsAuthorized(string userId, out string refreshToken)  
{  
    SqlConnection Con = new SqlConnection(ConfigurationManager.ConnectionStrings["DbConnection"].ConnectionString);  
    string Query = "select RefreshToken from Member where UserId=" + userId;  
    SqlCommand Cmd = new SqlCommand(Query, Con);  
    Con.Open();  
    var Result = Cmd.ExecuteScalar();  
    Con.Close();  
    refreshToken = Result != null ? Result.ToString() : string.Empty;  
    return refreshToken.Length > 0 ? true : false;  
}  
  
private string GetGmailId(string accessToken)  
{  
  
    if (accessToken.Length > 0)  
    {  
        string GmailId = FetchUsersEmail(accessToken);  
        return GmailId;  
    }  
    else  
    {  
        return string.Empty;  
    }  
}  
  
private string GetAccessToken(string refreshToken)  
{  
    string ClientSecret = ConfigurationManager.AppSettings["ClientSecret"];  
    string ClientId = ConfigurationManager.AppSettings["ClientId"];  
  
    var Content = "refresh_token=" + refreshToken +  
        "&client_id=" + ClientId +  
        "&client_secret=" + ClientSecret +  
        "&grant_type=refresh_token";  
  
    WebRequest request = WebRequest.Create("https://accounts.google.com/o/oauth2/token");  
    request.Method = "POST";  
    byte[] byteArray = Encoding.UTF8.GetBytes(Content);  
    request.ContentType = "application/x-www-form-urlencoded";  
    request.ContentLength = byteArray.Length;  
  
    using (Stream dataStream = request.GetRequestStream())  
    {  
        dataStream.Write(byteArray, 0, byteArray.Length);  
        dataStream.Close();  
    }  
  
    var Response = (HttpWebResponse)request.GetResponse();  
    Stream responseDataStream = Response.GetResponseStream();  
    StreamReader reader = new StreamReader(responseDataStream);  
    string ResponseData = reader.ReadToEnd();  
    reader.Close();  
    responseDataStream.Close();  
    Response.Close();  
    if (Response.StatusCode == HttpStatusCode.OK)  
    {  
        var ReturnedToken = JsonConvert.DeserializeObject(ResponseData);  
        return ReturnedToken.access_token;  
    }  
    else  
    {  
        return string.Empty;  
    }  
}  
  
private string FetchUsersEmail(string accessToken)  
{  
    var EmailRequest = @"https://www.googleapis.com/userinfo/email?alt=json&access_token=" + accessToken;  
    // Create a request for the URL.  
    var Request = WebRequest.Create(EmailRequest);  
    // Get the response.  
    var Response = (HttpWebResponse)Request.GetResponse();  
    // Get the stream containing content returned by the server.  
    var DataStream = Response.GetResponseStream();  
    // Open the stream using a StreamReader for easy access.  
    var Reader = new StreamReader(DataStream);  
    // Read the content.  
    var JsonString = Reader.ReadToEnd();  
    // Cleanup the streams and the response.  
    Reader.Close();  
    DataStream.Close();  
    Response.Close();  
  
    dynamic json = JValue.Parse(JsonString);  
    return json.data.email;  
}


What the above code is doing -
  • We will first check whether user is authorized or not.if authorize the "IsAuthorized" function will return RefreshToken as out parameter.
  • We will use that refresh token to get the access token.
  • After that by using access token, we will get the email id.
now, run the project and navigate to GetEmail.aspx and enter the user id and see the page in action.



Finally, We have successfully implemented the Oath2.o authrization for Google.

Interesting Points

Have you noticed, we are getting only email id, so what is the thing which is saying google that the system wants only email id - the scope is the thing that we send at the time of authorization to google to let google know that the requesting system wants this type of service. you can also send the multiple scopes to get the multiple service e.g - google contacts, google calender etc. Want to know, how we can get the google calender, google contacts or how we can upload the file on google drive. let's wait for my next article.

References

Comments

  1. Appreciating the persistence you put into your blog and detailed information you provide. Best Selenium Training in Bangalore

    ReplyDelete
  2. when data type is number it throws error, can u give example where data type is used as number

    ReplyDelete
    Replies
    1. I think you are asking about wrong article ? you mean article on jsstore right ?

      Delete
  3. Replies
    1. Thanks merlin, now i write at medium. You can read more awesome article there. Here is my medium profile - https://medium.com/@ujjwalgupta_57939

      Delete

Post a Comment

Popular posts from this blog

Angular4 Crud Operation In IndexedDB using JsStore V1

Introduction Are you facing difficulties using IndexedDB in angular4 or angular2 ? Well, you are reading the right article. You will be able to use IndexedDB all functionality in simple way after reading this article. In this article i am going to explain - how to do crud operation in angular4 using indexedDB wrapper JsStore. If you are thinking - what is JsStore ? JsStore is an IndexedDB wrapper. It provides simple sql like api to do db operations and makes IndexedDB simple. So In this article we will replace IndexedDB with JsStore . Enough of the words , lets do something. If you want the source code , you can download it from here - https://github.com/ujjwalguptaofficial/angular4.crud.jsstore Prerequisites You should have basic knowledge of  html css javascript angular2 or angular4 indexedb (not necessary) Let's Code Create Angular project First we will have to create a angular project. I am showing you how to do with angular cli. S