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