JavaScript authentication

When the Dashboard app performs the OAuth2 dance with Strava, it stores user information into the session, which is perfect to have the user authenticate the dashboard.

However, when the ReactJS UI calls the DataService microservice to display the user runs, we need to provide an authentication header.

There are the following two ways to handle this problem:

  • Proxy all the calls to the microservices via the Dashboard web app using the existing session information
  • Generate a JWT token for the end user, which they can store and use against another microservice

The proxy solution is the simplest one by all means, because it removes the need to generate one token per user for accessing DataService. It also prevents us from exposing DataService publicly. Hiding everything behind the dashboard means we have more flexibility to change the internals while keeping the UI compatible.

The problem with that approach, though, is that we are forcing all the traffic through the Dashboard service even when it is not needed. Ideally, updating the list of displayed runs should not be something that the Dashboard server should worry about.

The second solution is more elegant with the microservices design. We are dealing tokens, and the Web UI is just one of the clients for some microservices. However, that also means the client has to deal with two authentication loops. If the JWT token gets revoked, the Client app needs to authenticate back even if the Strava token is still valid.

The first solution is probably the best bet for a first version. Proxying calls to microservices on behalf of the user means that the Dashboard application uses its JWT token to call DataService to grab the user data.

DataService, as explained in Chapter 4, Designing Runnerly, uses the following API pattern to return runs: GET /runs/<user_id>/<year>/<month>.

If we make the assumption that the Dashboard keeps track of the (e-mail, user ID) tuples, the proxy view for that API can be GET /api/runs/<year>/<month>. From there, the Dashboard code can find back the user ID given the user e-mail currently logged into the session via Strava.

The proxy code can look like this:

    @app.route('/api/runs/<int:year>/<int:month>') 
def _runs(year, month):
if 'user' not in session:
abort(401)
uid = email_to_uid(session['user'])
endpoint = '/runs/%d/%d/%d' % (uid, year, month)
resp = call_data_service(endpoint)
return jsonify(resp.json())

The ;call_data_service() ;function calls the DataService endpoint with a JWT token, and email_to_uid() converts the e-mail to the corresponding user ID.

Last, to make sure this approach works, you need to use the withCredentials option on every xhr calls so that cookies and authentication headers are sent when AJAX calls are made.

    var xhr = new XMLHttpRequest(); 
xhr.open('get', URL, true);
xhr.withCredentials = true;
xhr.onload = function() {
var data = JSON.parse(xhr.responseText);
...
} .bind(this);

xhr.send();

In this chapter, we looked at how to build a ReactJS UI wrapped into a Flask application (Dashboard). ReactJS is an excellent way to build a modern interactive UI in the browser--it introduces a new syntax called JSX, which speeds up JS execution.

We also looked at how to use a toolchain based on npm, Bower, and Babel to manage JS dependencies, and transpile JSX files.

The Dashboard application uses Strava's three-legged OAuth API to connect users and get back a token from the Strava service. We made the design decision to separate the Dashboard application from DataService, so the token is sent to the DataService microservice for storage. That token can then be used by the Strava Celery worker to fetch runs on behalf of the user.

Lastly, the calls made to different services to build the dashboard are proxied through the Dashboard server to simplify the client side--which deals with a single server and a single authentication and authorization process.

The following is a diagram of the new architecture, which includes the Dashboard app:

You can find the full code of the Dashboard in the Runnerly org at https://github.com/runnerly/dashboard.

With now six different Flask apps that compose it, developing an application like Runnerly can be a challenge when you are a developer.

 

 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset