Secluded API Authentication With Rails 3 Using ActiveResource and Devise
I recently had to implement this workflow for a client project, and canada goose childrens coats outlet online got a little confusing. There’s a lot of example code floating around, but canada goose childrens coats outlet online took some trial and error to get everything working smoothly. So, on the off-chance it’ll be helpful for someone else, here’s a walkthrough that illustrates the complete package.
Caveat: ActiveResource has been removed from Rails core, and I hear there may be better solutions out there for interacting with remote APIs. At the outset of this project it seemed like the best way to quickly get canada goose childrens coats outlet online working, but your mileage may vary.
The basic architecture consists of two Rails sites:
The Backend: A pure JSON API that authenticates users via Devise’s token_authenticatable module. Uses ActiveRecord database models, no session storage.
The Front End: A client that signs users in by requesting and storing a token from the backend. Uses session storage and ActiveResource models.
I’ll talk about the configuration for each of these separately, and then some of the integration work (read: hacking) I had to do to get everything running smoothly.
Security Warning! This setup is completely insecure if used over HTTP (since email/password are sent in plaintext). You definitely want to ensure that your front end communicates with your backend strictly via HTTPS in order to protect against man-in-the-middle attacks.
This is covered well elsewhere so I won’t get into it. Add ‘devise’ to your gemfile and check out the Devise documentation for basic setup. RailsCasts are also a great resource for this.
The token_authenticatable module adds authentication tokens to a model and sets it up so Devise can use them to log users in.
First, we need a new database column. Older versions of Devise had the t. token_authenticatable shorthand for this, but that is now deprecated, so we need to set up the column and index manually.
Create a new database migration:
Tell Devise to use tokens for the User model by adding: token_authenticatable to the devise line in your model, e. g.:
Then a few small changes to the Devise config (config/initializers/devise. rb):
The first line tells Devise not to store the user in the session.
The second line changes what you’re going to call your authentication token parameter – I changed mine to “auth_token” because I didn’t want to be typing “authentication_token” all the time, but you can call it whatever you want (or leave it as the default).
Now any protected content needs to be wrapped with a filter that tells it to deny access if the user is not authenticated. In my Users controller, I added:
So now we have all the infrastructure in place. Next, we need a way to actually authenticate the user. That’s the job of the Sessions controller, which checks a given username and password and, if they’re valid, returns a token (as well as the ID of the user in question). Note that, since there’s no session-based sign-in on the backend, we never call Devise’s sign_in/sign_out methods. We’re just validating the password, making sure the user has an auth token generated, and returning it.
(In some sense, a user is “signed in” to the backend as long as they have a valid authentication token. If you want, you can expire this token after some period of time instead of having it stick around indefinitely. You could also reset it after a certain number of uses. )
On login, we call @user. ensure_authentication_token! to make sure the user has a token saved. You could also add this call to your User#create method to generate the token when the user is first created.
When the session is destroyed, we call @user. reset_authentication_token! to expire the current token and generate a new one.
The last piece of the puzzle is making sure you have sign_in and sign_out routes. This should actually be a given if you have Devise set up correctly, but just to cover all the bases, a simple devise_for call in config/routes. rb will route /users/sign_in and /users/sign_out to the right places:
Now you should be able to test the backend via curl or an app like HTTPClient. Here’s a quick cheat sheet to test that everything’s working properly. This assumes you’ve already created a user on the backend. Obviously, replace “localhost: 3000” with your test URL.
All good? Now we just have to set it up so the front end knows how to play this game.
The front end does not have Devise installed. We don’t need it, because the user and session models are so simple, almost stubs. All they do is add a layer of abstraction to the API calls. You could probably still use Devise to manage your sessions and templates, but since I’m using custom sign in and registration templates, it felt like overkill.
The user model on the front end is just an ActiveResource model whose site points to the backend URL.
We have another custom Sessions Controller on the front end which is responsible for managing login and logout. It sends the provided email and password to the backend and saves the returned token and user ID in the session cookie.