marc walter

Elm Oauth integration (2 of 2 - Google)

2018-06-17 (Last updated on 2018-09-07)

This extends the example GitHub OAuth integration with another OAUTH provider, namely Google.

For information about the general OAuth 2.0 flow, check out the first post in this series.

The only major difference is that google passes the server access key as part of a query parameter instead of the URL path.

Google integration

It follows the official google doc for server-side web apps and for JavaScript web apps.

A great help was the Google OAuth playground.

Using Google as identity provider

  1. Open the web app and start answering the question, then use Google to provide your email address
  2. Post current state to /auth/google/get-url
    • App state is stored in db with a random key
  3. Receive authentication URL
    • Contains a csrf token
    • Redirect url contains the key to restore the app state
  4. Redirect to Google servers
    • User authenticates and allows access
  5. Redirect to /auth/google?key
    • Rehydrate session on server
  6. App displays current state
  7. App communicates with server to retrieve an email address
    • App posts to /auth/google with body code and state
    • Server retrieves an access token from Google
    • Server queries Google for user data
    • Server answers to app with user's email
  8. App displays authenticated email address

Register an OAuth app

First, register a new OAuth application and specify the authorization callback URL. This is the URL that Google returns the user to after authentication.

Because I develop locally and my server runs at http://localhost:3000, I chose http://localhost:4567/oauth to allow room for further OAuth integrations.

After that, copy the generated Client ID and Client Secret.

1. Building an authentication URL

I only want the user's email address, so I limit my scope to email. All available scopes are documented on Google OAuth 2.0 Api Scopes.

Building the URL: https://accounts.google.com/o/oauth2/v2/auth?client_id=<client_id>&scope=email&redirect_uri=<redirect_uri>&response_type=code&state=<custom_data>

2. Redirecting the user to Google servers

Change the page.

3. Authentication on Google servers

User enters her credentials if she is not logged in already and approves access to her data.

4. Google redirects the user to the web app

Google passes the state passed into the authentication (which may be used for CSRF protection or exchange of app state) as query parameters e.g. /auth/google/?state=<state>.

5. Rehydrate the web app

Either the server parses the query parameters to fetch the users current state from a database, or the web app could use the state to inject it again.
The latter is not an option for me, because the state could contain personal data that should not be shared to an arbitrary other server in a country without proper privacy settings.

6. Create an API access token

Must be done on the server, you need the client id and the client secret of the OAuth app.
You need to POST to https://www.googleapis.com/oauth2/v4/token?client_id=<client_id>&client_secret=<client_secret>&code=<code>&grant_type=authorization_code&redirect_uri=<redirect_uri>. You may specify a data format in the HTTP Accept header, I used application/json.

7. Retrieve the email address

After the server receives the access token, it can GET https://www.googleapis.com/userinfo/v2/me to retrieve the user information including the email address. I set the HTTP headers Accept to application/json and Authorization to Bearer <access_token>

Overview

Server

HTTP Route Description
GET /index Serves the web app
POST /auth/google/get-url Receives the web app state and returns the redirect URL
GET /auth/google Serves the web app with saved web app state
POST /auth/google/ Receives the user code, communicates with Google servers, and returns the user's email address

Important bits

In elm/Main.elm:

  • The init function
    • When the user opens the index page, receives an empty JSON value and tries to decode it. If decoding is not successful, default data is used.
    • When the user enters from /auth/google, receives the question and (partial) answer from the server and displays it
    • When the user returns from Google, reads the user code and state from the URL and initiates retrieval of the email address
  • While the server queries Google servers for the email address, the user can continue working with the web app. The email address will be added when it arrives.

Download

The code written in JavaScript using koa for the server and in elm for the client is available on github.