Skip to content

Authentication

Katja Durrani edited this page Oct 29, 2017 · 4 revisions

Authentication with passportjs using GitHub and JWT strategies

Overview

To avoid having to handle user accounts and store passwords, we chose to use authentication via GitHub. This uses an OAuth process, during wich the user can authorise the application to have limited access to the user's account on Github (in our case only using publicly available data). The implementation of this process is simplified by using the PassportJS library and strategies that go with it.

Tools and Libraries used

How to make it run on your machine

The version in the git repository uses http://localhost:3000 as the root URL.

You will need to register an app and create a clientID and client secret here (or ask me for mine, then you can skip this step): https://github.com/settings/developers (under OAuth Apps) The crucial step here is to set "Authorization callback URL" to https://localhost:3000/login

Then, at root level, create a file called appConfig.js and add your clientID and client secret, as well as a secret string of your choice, in this format: module.exports = { GITHUB_CLIENT_ID: 'xxxxxxxxxxxxxxxxxxx', GITHUB_CLIENT_SECRET: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', secret: 'verysecretstringforsecurity' }

You will also need to create an Sqlite database file. This can just be an empty file: Cd into the auth-data directory. Create a data directory and in it a userdb.sqlite file: mkdir data && touch data/userdb.sqlite

Current strategy - rationale and possible improvements

The way authentication is implemented at the moment, is through passportjs with GitHub and JSON Web Tokens (JWT) strategies. As a first step, the user is authenticated via GitHub and redirected to a specified callback URL in the web app. At this point, a web token is generated on the server. The idea is to then pass the web token to the client to be stored in localStorage. From then on, with each http request, the token can be passed around with the header, and used by the JWT passport strategy to verify the user.

The user should at this point not need to log in with Github again. Even when the browser is closed, and the user comes back to the app another time, the web token is still there and will be used for authentication again, no need to log in again.

Implementing this presented a certain challenge though: Following the GitHub authentication, on receiving the reponse on the /login URL, we can generate a token on the server, but not easily pass it on to the client. To pass data directly into a component, it seems we would have to render it on the server.

Another thing we can do, is to redirect on receiving the response, but we then can't pass any data along. So I came up with this 'trick': On successful GitHub authentication, in the callback I save the publicly available user data to the Sqlite database, and also save a web token, generated using the Github user ID and the timestamp as payload. Then the user is redirected to a URL with the GitHub Id in it: /profile/[github_id]

The component rendered at this URL gets passed the ID parameter in the URL as a prop. It then makes an ajax call to the server, checking if a user with the ID is saved in the database. In addition, the token connected with that user is decoded, and the timestamp extracted from it. Only if the time difference between the stamp and the ajax call is less than 20 sec, the user data and the token are sent back to the component, and the token is saved to LocalStorage.

It would be good to find a different way. I am not sure if the combination of OAuth via GitHub and subsequent authoristaion via JWT is a good one, I have not seen any examples of it. On the other hand I do think it is better than using sessions, as sessions wouldn't allow requests to a different domain.

Implementation in our app

I have added a second page that details the implementation in our app (where methods, components etc can be found): Authentication-ctd-app-implementation

So, to sum it up, the authentication flow is like this: User clicks Log In button which links to /auth/github -> GitHub Authentication happens as defined in passport strategy, user redirected to /login, public userdata and token is saved on the server, redirect to /profile/[github_id] -> User data and token fetched from the server -> token saved to localStorage. Subsequent Http requests pass token via the Header, which serves to authenticate the user.

References

Technologies:

PassportJS: http://passportjs.org/
Sqlite: https://www.sqlite.org
Sequelize: http://docs.sequelizejs.com/

Documentation about Oauth:

An introduction to OAuth2 by DigitalOcean: https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2 Oauth Flow in Github: https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/

Tutorials and Articles:

Udemy S. Grider Tutorial: https://www.udemy.com/react-redux-tutorial
Node.js Express application with GitHub authentication: https://github.com/billyfung/node-beginner

Clone this wiki locally