Tuesday, May 23, 2017

Delphi OAuth2 Authenticator Component for Google

Delphi OAuth2 Authenticator Component for Google
Encapsulating a Perennially Irritating Task
  1. Reference

Links and comments are current as of May 23, 2017. Programming for Google is really like trying to hit a moving target with a bow and arrow. You may have to hunt around a bit to find what you’re looking for if you come across this blog a year or so from now.
  1. Component Code

The project that contains the component is available under the MIT License from https://github.com/Pasquina/GoogleOAuth2Authenticator. Please note some caveats:
  • No guarantees. Your risk.
  • The code has only been developed and tested using a VCL 32-bit application. It should work for Windows 64-bit, but I’ve never tried it.
  • With additional work, you might get this to work for Android and OS X.
  • FireMonkey is not currently supported. This is because the component instantiates a TWebBrowser component that is VCL-only. Additional code can probably extend the component for use with FireMonkey as well.
This is pretty much alpha level code, with lots of features yet to be added. If I ever need to, I may add them but right now I don’t plan on doing more work on this.
  1. Overview

Every time I need to write code to access a Google REST API I’m faced with the same tedious and error-prone task of coding the OAuth2 Authentication routines I need to gain access. The basic steps are:
  1. Determine all of the various endpoints, URIs, and other constants that Google requires for its implementation of OAUTH2. OAUTH2 is not really a protocol, but rather an “architectural style” so Google’s ideas are generally somewhat different from those of, say, Facebook or Twitter.
  2. Set up the target Google account to accept the necessary REST calls. This involves enabling the needed APIs (if not already enabled) and registering your application to obtain needed Client ID and Client Secret.
  3. Code the requisite browser object, provision it with the proper URL (concocted of many of the things mentioned previously), allow the user to authenticate and authorize your app for access, and finally scraping the reply screen for the needed Access and Refresh Tokens along with an Access Token expiry interval.
Adding to the confusion is the Embarcadero provided REST Debugger that sort of kludges together a bunch of different “architectural styles” from a variety of websites into a single monolithic blob of code that only a mother could love.
The DocWiki for RAD Studio Berlin is a much better source of information about the REST Client Library. See REST Client Library. The DocWiki suggests with reference to TOAuth2Authenticator: “Because of the heavy dependencies to the service providers, a generic component like this can only give some support and provide the infrastructure to follow the workflow of the service provider. You might want to inherit from this class to create an authenticator class specific to a service provider.”
That sounded like a pretty good idea to me, so that’s what the rest of this post is about. It’s actually pretty easy to do once you collect all of the detritus needed for creating the code.
  1. Finding Information and Preparing Google

    1. URIs and Endpoints

The easiest part of all of this is downloading Google's Well-Known Open ID Configuration. It has a couple of things you’ll need like the authorization-endpoint and token-endpoint. You’ll also want to take a look at OAuth 2.0 for Mobile & Desktop Apps. Scroll down to the redirect-uri values section, Manual copy/paste subsection. It says simply urn:ietf:wg:oauth:2.0:oob.You’ll need that later.
    1. Scopes

You’ll also need whatever API Scopes you intend to access. Visit OAuth 2.0 Scopews for Google APIs for a dazzling array of choices. You can use one or more than one in your application. When specifying multiple scopes they are separated by a space.
    1. Create a Project or Use an Existing Project

First, you’ll need to visit Google API Manager while you’re logged on as an administrator of the target Google Account. There’s a little obscure reveal-triangle near the top left of the screen. If you click that you can choose from an existing project or create a new one. If you create a new project you’ll be asked to give it a name.
    1. Enable the API(s) You Need

Next, choose the Dashboard menu item on the left and then click Enable API. This will reveal yet another dazzlilng array of choices. Click on the API you plan on using to display more information about the API. To enable the API for your project, click Enable at the top of the screen.
    1. Obtain Your Credentials

Click on the Credentials menu item to the left. If you plan on using credentials already created, simply click on the desired name I the OAuth 2.0 client IDs column. To create a new set of credentials, click the Create credentials button.
You can also delete credential sets if you decide you want to disable all access using the deleted set. If you lose your credentials, you can always return to this page to obtain them again.
    1. What’s Missing?

You should now have all the information you need to Authenticate your Google app. What’s missing? Actually, we haven’t talked at all about the REST requests you’ll need to make to get your app to do useful work. For a list of Google APIs, visit Google APIs Explorer. The possibilities are staggering and well beyond the scope of the present post. It is assumed that you know what you want to accomplish, and it’s simply a matter of making the proper requests to the appropriate Google API.
  1. Using TOAuth2AuthenticatorGoogle

    1. Configuring the Components

Drop the following objects on a form: (A data module works well.)
  • TRESTClient
  • TRESTRequest
  • TRESTResponse
  • TOAuth2AuthenticatorGoogle
  • TRESTResponseDataSetAdapter (Optional if you want to convert the response JSON to a dataset.)
  • TFDMemTable (Optional if you want to convert the response JSON to a dataset.)
Connect the components in the customary fashion. Configure your TRESTRequest to make the appropriate request for what you intend to accomplish. The DocWiki page REST Client Library has some excellent points about TRESTClient and TRESTRequest. Give some attention to properly configuring the following properties:
  • Base URL (TRESTClient)
  • Resource (TRESTRequest)
  • URL Segment Parameters (TRESTRequest) that make “substitutions” in the query string
  • Other parameters (TRESTRequest)
  • Cookie Parameters
Finally, be sure to configure TOAUTH2AuthenticatorGoogle correctly. The properties you should already have if you have followed all of the steps above are:
  • AccessTokenEndpoint
  • ClientID
  • ClientSecret
  • LoginHint (this is a Google feature and if you know your anticipated username for the authentication, specifying it in this parameter will help speed the authentication along)
  • RedirectionEndpoint—remember urn:ietf:wg:oauth:2.0:oob? Here’s where it goes.
All other properties can be left at their default values. Please note, the AccessToken property is used by the component to decide whether OAuth2 must be used when the RESTRequest is made. Leave it blank and OAuth2 will be invoked to fill it in. To force your app to reauthenticate, set this property to blanks and it will reauthenticate at the next request.
    1. Invoking Authentication

Authentication is not a separate step using this component. It is an automatic part of making a REST Request. Thus, in order to authenticate, you must have a valid REST Request configured. For example, you might want to retrieve a list of G Suite Users. To do this, configure the Authenticator properties with the necessary endpoints for authentication and also configure the TRESTClient and TRESTRequest to make the customary API request for users. Then invoke the Request: e.g., YourRESTRequest.Execute; authentication is an automatic precursor to executing the API request.
    1. Component Code

Component code is straightforward. If you download the code from GitHub you can easily follow the explanation that follows:
      1. Procedure DoAuthenticate; override;

This is the control routine for authentication. When a REST Request is made (for example, for a list of G Suite Users) this routine handles necessary authentication. After authentication, normal processing is resumed using the inherited keyword.
      1. Procedure WebFormTitleChanged

This is an event handler for the TWebBrowser object that is instantiated to prompt the user for authorization. It scans the title string for the authorization code returned by Google. Upon finding the code, it saves the code and closes the Web Browser.
      1. ProcedureGetAuthCodeGoogle

This routine instantiates a TWebBrowser, builds the appropriate URL, and then displays the Web Browser with the URL that causes the appropriate authentication request to be made to Google. The user then interacts with the response, and if the request is approved, Google returns an authorization code that is extracted by WebFormTitleChanged.
      1. ProcedureGetTokensGoogle

This is the final step in OAuth2 Authentication. After the authorization code has been obtained successfully, DoAuthenticate invokes this routine that builds a TRESTClient object and a TRESTRequest object. The Request parameters ask to exchange the authorization code for the Access Tokens and Token Expiry. If successful, the Response contains the tokens and expiry interval in seconds. These are extracted and appropriately stored for later use. Note that it is not necessary to construct a Response object; if none is specified in the Request object, the Response is created automatically.
  1. Conclusion

For me, OAuth2 is a major distraction from actually getting an application to run. This somewhat trivial component has helped me to organize my efforts and get on with the real point of my development efforts.
I hope it helps you, as well.
Comments and corrections welcomed.


1 comment:

  1. Thanks for the tips!

    Converting to FMX should be easy, because there's a corresponding FMX unit: REST.Authenticator.OAuth.WebForm.FMX

    ReplyDelete

FireMonkey String Grid Responsive Columns

FireMonkey String Grid Responsive Columns Code to Cause Column Widths to Change When String Grids Are Resized Overview I have a FireMonke...