Elm Oauth integration (1 of 2 - GitHub)
2018-06-16 (Last updated on 2018-09-07)
Background
I am working on a web service that a user may access without registration, but where she may invite other people via email.
To mitigate misuse of the service for spam, I decided to require a validated email address before the user may invite someone else. One simple way is to send a registration email to the user to activate the feature.
But I also want the possibility to add the email feature without requiring the user to wait for an email.
To achieve this, I decided to use OAuth 2.0 integration, and first use GitHub.
TLDR: Example code written in JavaScript with koa for the server and in elm for the client is available for download and on github.
GitHub integration
Note: This follows the official documentation on authorizing OAuth apps.
General OAuth 2.0 flow
- Generate a GitHub authentication URL
- Redirect the user to GitHub
- User enters her credentials to confirms provide her identity
- User is redirected back to your site by GitHub
- Rehydrate the web app using the returned information
- Generate an access token for the GitHub API
- Retrieve the email address
Register an OAuth app
First, register a new OAuth application and specify the authorization callback URL. This is the URL that GitHub 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 a GitHub authentication URL
I only want the user's email address, so I limit my scope to user:email
. All available scopes are documented on github.
Building the URL:
https://github.com/login/oauth/authorize?client_id=<github_client_id>&scope=user:email&state=<custom_data>
2. Redirecting the user to GitHub
Change the page.
3. Authentication on GitHub
User enters her credentials if she is not logged in already and approves access to her data.
4. GitHub redirects the user to the web app
Github passes a user code and the state passed into the authentication (which may be used for CSRF protection or exchange of app state) as query parameters e.g. /auth/github/?code=<code>&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 service in the US of A.
6. Create a GitHub 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://github.com/login/oauth/access_token?client_id=<client_id>&client_secret=<client_secret>&code=<code>&state=<state>
. 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://api.github.com/user
to retrieve the user information including the email address. I set the HTTP headers Accept
to application/json
and Authorization
to token <access_token>
Overview
Server
HTTP | Route | Description |
---|---|---|
GET | /index | Serves the web app |
POST | /auth/github/get-url | Receives the web app state and returns the redirect URL |
GET | /auth/github/ |
Serves the web app with saved web app state |
POST | /auth/github/ |
Receives the user code, communicates with GitHub, and returns the user's email address |
Important bits
In server.js:
- When generating the GitHub authentication URL, I also added a redirect_url, which contained the database key of the current transaction, this allows me to retrieve the user's state. It is not necessary here, but for instance google auth does not use query parameters, but appends it after a '#', which is not sent to the server.
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/github/
, receives the question and (partial) answer from the server and displays it - When the user returns from GitHub, reads the user code and state from the URL and initiates retrieval of the GitHub email address
- While the server queries GitHub 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 for download and on github.