Token-Based Authentication with Rails and Ionic

R. Wolf
Philosophie is Thinking
3 min readSep 17, 2015

--

Here at Philosophie NYC, we’ve been experimenting a lot with building hybrid HTML5 iOS apps for our clients who need mobile solutions, rather than going full native. Our go-to solution has been Ionic, a framework that blends Angular and Cordova, allowing us to build single-page HTML/JS applications that are then wrapped as native iOS apps and deployed to devices.

For most of these projects, we have a Ruby on Rails API backend working in conjunction with client-side Ionic applications. Seeing as data is persisted through the API rather than through the client, this setup necessitates that we have some sort of token-based authentication system that can work between both the client and server components of the application. Token-based authentication between the client and server allows us to authorize and identify iOS users on server-side and persist their client-side session on the API side. While there are lots of great token-based client/server authentication methods available (e.g. JWT), I realized that there wasn’t a lot of information on how these solutions actually functioned from a high/mid-level standpoint. So this article is going to cover a simple implementation of basic client/server token-based authentication setup, using a hypothetical application consisting of an Ionic client application and Rails API server without relying on open source libraries to abstract the logic away.

The round-trip authentication flow will be:

  1. User logs into the application with the client-side Ionic application
  2. Server validates user
  3. Server generates an auth token and sends it as a response to the client
  4. Client sends the auth token as a header on each subsequent request
  5. Server uses auth token to validate and identify user

Once the user has entered their email and password on the client-side application, this information will be sent to the Rails server for validation. The server will have to first verify that the user’s password is correct, and if so generate and return an auth token (and respond with an error if the password is not correct). For the sake of example, let’s assume the User model server-side will be managed through Devise, and that the User model has a database string attribute of ‘auth_token’. The controller endpoint for this flow would look something like:

Then in the User model, we can implement the `fetch_auth_token!` method, which will create a new authentication token and set it as the `auth_token` attribute on that User instance:

The advantage of this approach is that each time the user logs in, a new auth token will be generated, which is more secure than having a single static auth token for each user.

Client-side, once that token is returned with the response on a successful authentication request, it needs to be stored and then sent as a header in any subsequent requests. Assuming our client application has a landing page with a LandingController, the code to store it could look like:

Now that the authorization token is stored client-side, the next step is to make that the auth token is passed as a header attribute in each subsequent API request. A good approach to this in Angular is is to create an intercepter service to do this for you:

And the last piece of functionality to add client-side is to push the service to the $httpProvider module:

Now, server-side, you can use this authorization token to ensure that the user has a valid authenticated session and to identify the user with each subsequent request:

I’ve found that writing our own authentication system oftentimes is easier than trying to keep two open-source libraries (client-side and server-side) in sync, but YMMV; the answer for most applications lies somewhere in the middle. Regardless, even if you end up going with a pre-written auth library, it’s always good to understand how to implement its component features, even if you don’t necessarily do so on that project.

Let me know any questions in the comments!

--

--