OAuth 2.0 Simple Example

Hey folks. I know that there are many of these pages out there
that try to explain how OAuth 2.0 works, but I still spent the better
part of the day figuring it all out so I thought that this document
was warranted. This is also written for future me.

The best page that I found
was Google's OpenID Connect page. It went about 90% of the way there
although better examples and more details about the final JWT payload
would have been good. I also used the JWT
IO home page and their cool web-tool. More on that later.

Background

Ok. Before we get into the details it's important to remember
what we are trying to do here. OAuth allows us to use the
authentication from a OAuth provider (like Google) instead of forcing
a user to provide username and password into your site. It suffers
from the issue that often when you log into Google (or other
providers), they provide information like email-address to the sites
you are trying to authenticate with, sigh, but I guess people are cool
with that or something.

Registering Your Application

Before you start coding, you will need to register your
application with the OAuth provider. In our case, we go to the
following
credentials list in Google. You will need a Google-id for this.
On Google you do something like the following.

Create an application

Add content to the consent screen like title and logo

Add credentials, specifically an OAuth 2.0 client ID

Choose the "Web application" type and give it a name

Enter the URIs that are allowed to be redirect-URIs

Google then gives you a client-id and secret that you will need to
record and use in your web and server code. For this example, Google
gave us:

The JWT token can then be verified against Google's published
signatures, and you can do other things with the access-token over time.

Let's break these steps in the process down. We will be using
Google API URLs in this example but I hope that Yahoo and other
providers are at least similar.

User Goes to Your Web Server

You have some sort of login page on your web-server
("/login.html") which asks for a username and password. It also has a
link or a clickable image to login using the user's Google account.
The URL to Google is something like:

https://accounts.google.com/o/oauth2/v2/auth

It also includes the following URL parameters and is URL-encoded:

client_id=... - Given to you when you register your application with the OAuth provider.

response_type=code - I think this is a constant.

scope=openid%20email - In Google's docs they say that this is a constant.

redirect_uri=... - URI that you configure with Google which is
an approved location for redirecting back to. This (like all params)
must be URL
encoded. See the example below.

state=... - Secure string that your server makes which should be
stored in the user's session. This gets returned in the callback
after the user logs in using the OAuth provider and should be validated at that
time.

login_hint=email-address - optional, if already known

openid.realm=256stuff.com - optional, your domain name, not sure how used

hd=256stuff.com - optional, the hosted domain, not sure how different from realm. It should be your domain.

Here's an example URL with all of the parameters. It has some whitespace for readability:

User Clicks on the Login With Google Button

Click.

Google Presents Some Sort of Confirmation Page

The OAuth provider will present the user with a page something like:

256stuff.com OAuth Sample would like to ...

It is important to note that if the user is already logged in and
already confirmed the particular application, the OAuth provider will
not show any confirmation page but will redirect immediately back with
the approval information. Pretty cool. If you want to removed a
connected application, you can do it in your
Connected apps & sites section on the OAuth provider.

User Denies the Auth Request and Google Redirects To the redirect_uri

If you deny the request, the OAuth provider will redirect you back
to the redirect URI provided in the request (redirect_uri). Here's
the full redirect URI of the deny result with added whitespace:

Well why did you click on the "Login With Google"
button if you were just going to deny it fool?!

User Approves the Auth Request and Google Redirects To the redirect_uri

If you approve the request (good dog), the OAuth provider will
redirect you back to the redirect URI provided in the request
(redirect_uri). Here's something like the full redirect URI of the
approval result with added whitespace:

state - the state parameter that you generated and sent in the OAuth request URL

code - authentication code that we will verify in the call below

authuser - not sure about this

prompt - whether or not the user actually confirmed the auth request or did they do it already ('content' or 'none')

session_state - some sort of Google session information

If Approved, Your Web-Server Needs to Validate the Response

This is designed to not involve the user's browser since you are using the client-secret here.
The request is made using a CGI script or in a controller.

After checking for approval, your web-server code should then
validate that the state parameter from the redirect is the same that
was stored in the user's session. Checking the state is important to
protect
against Cross-Site Request Forgery attacks. Your web-server code then
needs to take the code parameter and call back to OAuth provider to
validate it and turn it into an access-token. You web-server code
should send a POST to the URL:

This is a POST request made to a secure URL by your web-server
code and not through the user's browser. The request should
look something like the following, again minus the whitespace in the
params section. Notice that as always, the parameters must be
URL
encoded.

Google Returns Access-Token and JWT Information

If denied, a 404 or other status-code is returned. For example,
this happens when you make 2 requests for the same code. If
confirmed, the response to this API call should be a block of
information in JSON format that either validates or denies the code
parameter.

The 3rd block is base64 encoded signature bytes that can be used
to compare with the signature generated by the algorithm specified in
the header against the full payload JSON string. You will need to
download the keys from Google which can be found by looking at the
jwks_uri field in
the OpenID configuration document which right now (12/2015) points
to v3 certs.
Google's docs say that these keys are changed "infrequently" like
"once per day" (sic) so they can be cached but not for long. For more
info
see Google's discovery document.

It will say
that you are going to be sharing your email with me. All I can do is
promise that I'm not going to do anything with it aside from showing
you the auth results. It won't show up in my web-logs either. If you
are not convinced (and why would you be), you should create a
throw-away gmail account.