CBT Nuggets

Part 5: Authorization Grant, Our First OAuth Dance Steps

by Ben Finkel
Part 5: Authorization Grant, Our First OAuth Dance Steps picture: A
Follow us
Published on March 23, 2016

This is part five of a tutorial blog series from Ben Finkel addressing the challenges, solutions, and implementation of sound authentication. By the end of this series, you will be confident in your ability to implement an authentication system, even with little to no background.

The first leg of the OAuth Dance is the Authorization Grant.* This is the phase where the user of our app gives the provider permission to share our data. We "grant" the requested "authorization," hence the name of this step. In this post we'll setup our OAuth library and expand our main application to take advantage of it.

Scaffolding Our App

It's important that we structure our library such that it is:

  1. Intuitive to parse and understand;

  2. Relatively easy to integrate with an application, and

  3. Still flexible enough to handle the vagaries of OAuth.

Here is a general overview of how we can do that. Our application-specific code will be kept in a main.py file. This will represent whatever app is implementing OAuth. Everything OAuth-specific will be imported via a single import line from OAuth.py.

OAuth.py will contain all of our OAuth-specific code. For any functions that are provider specific, we will import a provider .py file into OAuth.py. If we code it right, adding a new provider should be as easy as copying an existing provider's .py file, making the necessary adjustments, and importing it into OAuth.py.

The code for this post is available at the public GIT repo linked at the end of the post.

The Consumer App

Our app.yaml file does not need to change from the previous post; here it is for reference:

Feel free to change the version if you'd like to have both the old and new versions running live in production. Otherwise, when we deploy, the new copy will overwrite the previous copy.

Main.py has quite a few additions, so let's cover them step-by-step.

We need to import OAuth (don't worry, we'll create it below) as well as a utility library. The utility library could be written directly in main.py, but for clarity, I broke it out. More on that file in our next post.

After our imports, we've got two global constants.

  1. privateAppKey is, just like it says, a private app-specific key used for the creation of state tokens (more on that later) and our session store.

  2. redirect_uri is the url in our app that will handle the callback after the provider goes through the grant process. Note: this is in main.py since this uri will change from consumer to consumer app.

The next section of main.py creates a new class called BaseHandler. This is just a wrapper for webapp2.RequestHandler, and allows us to create a session store that we'll use later. All of our subsequent router handlers will derive from BaseHandler. See the documentation on webapp2's session store here.

The MainPage class has been updated to display a link to our SignIn router ("/signin") and pass the provider in the querystring. This allows you to choose which providers to expose to the user right in your HTML template.

Two additional classes have been created for handling routes. SignIn is the class that handles when the user wishes to sign into our app. OAuthCallback is the class that will handle the post-grant callback from the provider to our app.

SignIn extracts the provider from the query string (only 'google' is an option so far, but we'll be expanding), generates a state token (more on that in the next post), and then passes those two pieces of info, along with our redirect_uri constant, to the OAuth library. In return, it gets a URL, which we then redirect to with self.redirect(author).

Our final step in main.py involves setting up the session store's configuration, expanding our app's routes, and adding the config variable to the app object.

The OAuth Layer

Our OAuth.py file is initially very simple.

First, we import our provider-specific OAuth libraries (just googleOAuth.py so far) and then create a map of provider strings for library functions. This allows us to call the proper function without an ever-growing Switch statement programmatically.

The implementation of the SignIn function is fairly straightforward. We look up the proper function from the earlier map based on the provider that was passed in, then call that function to get our URL. We return the resultant URL to the calling application (our consumer).

A Provider Implementation

This is the basic structure we'll use for all our OAuth providers.

First, we establish our auth endpoint with a constant. This will change for each provider. As we expand the functions of any given provider, additional endpoints will be stated here.

The second statement is our parameters collection, which we'll need at various points during the OAuth process. It is based on various sources.

  • Response_type for our purposes: this will always be 'code.' See RFC6749 for more details on how this is used.

  • Client_id: This is our application-specific client_id generated during post #4 (see Step 3).

  • Scope: This represents the permissions we are requesting. Initially, I'm using the same calendar scope we used in the OAuth playground during Post #3. Eventually, we'll want to replace this with something more specific**.

The SignIn function implementation here fills in the last two empty values in our parameters collection, state, and redirect_uri. These are passed in from our consumer app via the OAuth.py library. We build an appropriate URL and pass it back.

You can now deploy this application to your appspot.com/ URL. Launch the App Engine Launcher and either run the site locally or deploy it to the Google Cloud Platform (see the previous post for detailed instructions). Having done that, our website is a simple page with a link to sign in with Google. Following that link should redirect you to the Google OAuth landing page. If you're not already signed into Google, or if you have multiple accounts, you'll have to sign in.

Once you've signed in, you get an Kill! Don't worry, that's expected. Extra credit if you know why you got that Kill and how to correct it. We'll come back and resolve that issue in a little bit.

For now, rejoice! You've completed Step 1 of the OAuth Dance: The User Authorization Grant.

You can read the full tutorial series in these weekly installments:

Part 1: Authentication for the Modern Web

Part 2: Delegating Authentication

Part 3: Let's Play on the OAuth 2.0 Playground

Part 4: Let's Start Running Code

Part 5: Authorization Grant, Our First OAuth Dance Steps

Part 6: Authorization Request, An OAuth "State" of Mind

Part 7: Authorization Grant, Final OAuth Dance Steps 

Part 8: Expanding our Service with Github

Part 9: OAuth 2.0: Authorization, Not Authentication

The series will conclude in April 2016.

* In a 2-legged OAuth flow the grant step still happens, it's just done ahead of time by the developer. The authorization token is produced and shipped with the application so it implicitly has this grant. That's why 2-legged OAuth is also known as Implicit Grant.

** Here you can see the first signs of OAuth-as-Authentication cracking. We need to browse the Google-specific library of scopes to find what we want. What we want may not even be offered. OpenID Connect solves this for us.


Ultimate Systems Administration Cert Guide

By submitting this form you agree to receive marketing emails from CBT Nuggets and that you have read, understood and are able to consent to our privacy policy.


Don't miss out!Get great content
delivered to your inbox.

By submitting this form you agree to receive marketing emails from CBT Nuggets and that you have read, understood and are able to consent to our privacy policy.

Recommended Articles

Get CBT Nuggets IT training news and resources

I have read and understood the privacy policy and am able to consent to it.

© 2024 CBT Nuggets. All rights reserved.Terms | Privacy Policy | Accessibility | Sitemap | 2850 Crescent Avenue, Eugene, OR 97408 | 541-284-5522