OAuth 2.0 Implementation in Manifold

This page is meant to be a guide on how Manifold implements client side OAuth 2.0. It is not a guide on OAuth 2.0 itself. If you need a refresher on OAuth, or would like to learn it for the first time, this is a helpful resource: https://aaronparecki.com/oauth-2-simplified/. This page also does not describe the initial registration with the authorization/API server. That is described in Setting up Manifold.

The Initial Request

When an owner first navigates to the Manifold SPA (usually localhost:3000 for development), a check for current login information identifies that the owner is not logged in, and they are presented with the login page:

This page allows Manifold the flexibility of authenticating with any pico engine anywhere, rather than being hard coded into the login page. The owner/user may therefore use whatever engine fits their needs best. Or, they could use the default engine (not currently set up) by clicking Authorize on the right block.

Clicking the Authorize button will kick off the OAuth process by reaching the pico engine on whatever server was specified by the owner. This includes the state, client_id etc. as specified in OAuth.

The Code

The initial code for checking if a user is logged in is located in index.js:

<Route path="/" name="Home" render={requireAuth}/>

 requireAuth is a function defined in the utils folder. It performs a check to see if a user is logged in, and if they are not, it redirects the user to the login page, otherwise it returns the main container component for our app:

requireAuth(){
  if(!isLoggedIn()){
    return <Redirect to='/login' />
  }
  return <Full />
}


The actual code for redirecting the browser to the authorization server is found under the pages folder in Login.js:

<form className="card-block" onSubmit={handleSubmit(this.onSubmit.bind(this))}>


You can look at that same component for the handleSubmit implementation, but the function simply reassigns the window javascript variable to redirect the browser.

Receiving the Authorization Code

Once the authorization server has finished processing the initial request, and the owner hits approve on the auth server's site, the owner is redirected by the auth server to manifold's domain at "/#/code". This renders the Code component from the following in index.js:

<Route path="/code" component={Code}/>

The Code component contains a React function called componentDidMount(), which runs as soon as the component is rendered in the browser. This function is implemented to make the state checks as per the OAuth specs and, if everything checks out, dispatch an action to the redux store. That action (named getAccessToken) will make the final http call to get the access token. If you look at the file, you'll see that the action makes an axios call (which will return a promise) and then returns the action object with the payload variable set to a promise. As a reminder, the redux-promise middleware will notice the payload variable and the fact that it is a promise, intercept the action, and wait for the promise to resolve. Once the promise is resolved, the response (which should be the successful result from the axios call to get an access token) will go to the reducers. 

The reducer_oauth.js file handles this result and saves the access token (in this case the access token is an eci to the manifold owner pico) into the redux store and into local storage.

That is the end of the OAuth implementation. It would be of interest, however, to notice that this is an eci to the owner pico, and not the manifold pico. When the <Full /> container component is about to be rendered, it dispatches an action to retrieve manifold pico eci using the redux store and redux-saga. The latter package allows an exponential back-off implementation for retrieving the eci to mitigate race conditions in case the manifold pico is not finished being created by the time the request for its eci is made.

Copyright Picolabs | Licensed under Creative Commons.