2018-06-16 (Last updated on 2018-09-07)
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.
Note: This follows the official documentation on authorizing OAuth apps.
- 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
First, register a new OAuth application and specify the authorization callback URL. This is the URL that GitHub returns the user to after authentication.
After that, copy the generated Client ID and Client Secret.
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:
Change the page.
User enters her credentials if she is not logged in already and approves access to her data.
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.
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.
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
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
|GET||/index||Serves the web app|
|POST||/auth/github/get-url||Receives the web app state and returns the redirect URL|
||Serves the web app with saved web app state|
||Receives the user code, communicates with GitHub, and returns the user's email address|
- 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.
- 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.