Google+ Server Side flow in C#

Out of date

Heads up dear reader, a whole lot has happened in the past 18 months and so this post is out of date. Please read my latest here – How to: OAuth 2.0 Flows in .NET using C# for updated guidance and a new .NET Authorization sample!

Also, you can read the official sample documentation online here.

Overview

I recently was looking into creating a server-side application using the Google+ API and the .NET library. It’s slightly different from doing a client-side application in C# or a Windows store app.

What’s different is that the client library will take the HTTP context from your server, then run the user through the authentication flow, finally giving you back a client with an access token and a refresh token.

If you have Visual Studio and Windows, you can download the sample app. If you don’t have Visual Studio, you can download Visual Studio Express from MSDN to try this out.

Setting up new projects

Although you will not need to perform these steps if you’re starting from the sample, you will need to do the following steps if you are interested in creating a new project from scratch with the client libraries:

  1. Get the latest version of the .NET library, which can be downloaded from here:
    https://code.google.com/p/google-api-dotnet-client/wiki/Downloads
    The “Binary Release” zip is all you need unless you want to debug into the various generated service libraries.
  2. The project needs to be set up with the references you downloaded.
    The following image shows you the references I have added:

 

Once you have all the requisite references set up, you should be able to access the client libraries from your app.

Running the sample

If you are trying the sample app, you will need to get a client id from the Google APIs console. Services, origins, and redirects for this client id must be turned on as described in the client-side flow.

The following image shows the only services I’ve turned on:

 

Next, you will need to add your authentication page to the list of Redirect URIs.  In this example, mine is localhost:8080/auth.aspx, so my console looks like the following image (Client ID  / secret omitted):

Next, enter the client id and client secret in the wrapper class, PlusWrapper.cs, replacing YOUR CLIENT ID HERE and YOUR CLIENT SECRET.

        private static class ClientCredentials
        {
            // These come from the APIS console, https://code.google.com/apis/console
            static public string ClientID = "YOUR CLIENT ID HERE";
            static public string ClientSecret = "YOUR CLIENT SECRET";
        }

Click the run button in Visual Studio and the sample will start, opening the index for the site.  You will get a folder like the following:

 

Open auth.aspx and the server will walk you through the authorization flow. When you are done, you will see your profile rendered as follows:

How it works

The following code shows how the the Authorization flow is kicked off.

        // RefreshService
        /// <summary>
        /// Ensures that the current Plus service is authenticated and valid
        /// </summary>
        private void RefreshService()
        {
            // Create the service.
            if (plusService == null)
            {
                // Register the authenticator.
                var auth = CreateAuthenticator();
                plusService = new PlusService(auth);
                if (plusService != null)
                {
                    PeopleResource.GetRequest prgr = plusService.People.Get("me");
                    me = prgr.Fetch();
                }
            }
        }

        public Person Authenticate()
        {
            // Use the client to perform all of the Auth steps.
            RefreshService();

            // Now we should have the Plus service object, use it to perform a simple operation.
            return me;            
        }

For convenience, the method Authenticate is called in the wrapper class. This is done to retrieve the current user who is signed in. When the user is retrieved, the PlusService object is lazily instantiated  by calling the RefreshService method. This method will try and create a valid state object so that the client library can perform queries. Let’s take a look at the code which will try to create an OAuth2Authenticator object, used to build the IAuthorizationState object instance, state:

        // CreateAuthenticator
        /// <summary>
        /// Creates the authenticator for the server-side flow.
        /// </summary>
        /// <returns>An authenticator to be used for queries</returns>
        private OAuth2Authenticator<WebServerClient> CreateAuthenticator()
        {
            // Register the authenticator.
            AuthorizationServerDescription description = GoogleAuthenticationServer.Description;

            if (description.AuthorizationEndpoint.AbsoluteUri.IndexOf("offline") < 1)
            {
                description.AuthorizationEndpoint = new Uri(description.AuthorizationEndpoint.AbsoluteUri + "?access_type=offline");
            }

            var provider = new WebServerClient(description);
            provider.ClientIdentifier = ClientCredentials.ClientID;
            provider.ClientSecret = ClientCredentials.ClientSecret;

            var authenticator =
                new OAuth2Authenticator<WebServerClient>(provider, GetAuthorization) { NoCaching = true };
            return authenticator;
        }

        // GetAuthorization
        /// <summary>
        /// Gets the authorization object for the client-side flow
        /// </summary>
        /// <param name="client">The web server client used for authorization</param>
        /// <returns>An authorization state that can be used for API queries </returns>
        private IAuthorizationState GetAuthorization(WebServerClient client)
        {
            // If this user is already authenticated, then just return the auth state.
            IAuthorizationState state = _authstate;
            if (state != null)
            {
                return state;
            }

            // Check if an authorization request already is in progress.
            HttpRequestInfo reqinfo = new HttpRequestInfo(HttpContext.Current.Request);
            state = client.ProcessUserAuthorization(reqinfo);

            // Check to see if we have an access token and use that to generate the state.
            if (_accessToken != null)
            {
                state = CreateState(_accessToken, true);
                // Check to see if we have a refresh token and use that to get the auth state.
            }
            else if (_refreshToken != null)
            {
                state = CreateState(_refreshToken);
                bool worked = client.RefreshToken(state);
                if (state != null)
                {
                    return state;
                }
            }

            if (state != null && (!string.IsNullOrEmpty(state.AccessToken) || !string.IsNullOrEmpty(state.RefreshToken)))
            {
                // Store and return the credentials.
                HttpContext.Current.Session["AUTH_STATE"] = _authstate = state;
                _accessToken = state.AccessToken;
                _refreshToken = state.RefreshToken;
                return state;
            }

            // Otherwise do a new authorization request.
            string scope = PlusService.Scopes.PlusMe.GetStringValue();
            OutgoingWebResponse response = client.PrepareRequestUserAuthorization(new[] { scope });
            response.Send(); // Will throw a ThreadAbortException to prevent sending another response.
            return null;
        }

When the CreateAuthenticator method is called, parameters, such as the client ID and secret, are built into a provider object. This provider can be used to then perform authorization against the Google OAuth 2.0 endpoint. Because the client is performing a server-side flow, a WebServerClient is used to take over the user experience until the user is done with the authentication flow. At the conclusion of the authorization flow, you can retrieve the access token and the refresh token. These tokens can then be used to either re-establish state or to perform authenticated queries against the Google+ APIs. For convenience, another method is implemented for building the state object from cached tokens:

        // CreateState
        /// <summary>
        /// Creates a state object from a refresh token or access token.
        /// </summary>
        /// <param name="refreshToken">The refresh token from an authorization response.</param>
        /// <returns>A generated authorization state.</returns>
        private IAuthorizationState CreateState(string token, bool isAccessToken = false)
        {
            string[] scopes = { PlusService.Scopes.PlusMe.GetStringValue() };
            IAuthorizationState state = new AuthorizationState(scopes);
            if (isAccessToken)
            {
                state.AccessToken = token;
            }
            else
            {
                state.RefreshToken = token;
            }
            return state;
        }

When the state is recreated, subsequent calls to RefreshService will build out all of the required authentication pieces without needing any interaction from the user. Rebuilding the state is done in the following order:

  • From a new authentication code
  • From a valid access token
  • From a refresh token
  • Using the authentication flow from the client library
Once you have the PlusService object (plusService), you will have the credentials you need to perform authenticated actions on behalf of the user.  The example in Authenticate is retrieving the user’s public profile data as a Person object. In auth.aspx, the user is retrieved before the page loads. The following code shows how this is done:
        public Plus.v1.Data.Person me;
        protected void Page_Load(object sender, EventArgs e)
        {
            GPlusWrapper.PlusWrapper pw = new GPlusWrapper.PlusWrapper();
            me = pw.Authenticate();
        }
What this will do is place the Person object, me, into the current page’s scope. The following code shows how the profile data can then be accessed on the page.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="auth.aspx.cs" Inherits="GPlus_ServerSideFlow.auth" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>    
    <div>
        <div>Name: <%=me.DisplayName %></div>
        <div>Tagline: <%=me.Tagline%></div>
        <div><img src="<%=me.Image.Url%>" /></div>
    </div>    
</body>
</html>

Members of the me instance are now accessible on the page because the object was returned from the call to Authenticate made using the wrapper class. What is also interesting is that the server now has credentials for re-authenticating the user.

Closing thoughts

Although I didn’t expect it to be too difficult, I was still surprised with how easy it is to access the Google+ API from server-side flows. If you’re building a service or application that can use the library, you can get started very quickly, jumping right into accessing the available Google+ APIs. If you are a developer working on a Microsoft web stack, you should try playing with what’s available from Google+.