ruby-on-railsrubyauthenticationdeviseactiveresource

Authenticating requests using ActiveResource and session tokens


I have a rails API and a rails client app that communicate with each other via ActiveResource. This works great until I need to pass a unique token with each ActiveResource request to authenticate the user. From what I understand, the ActiveResource token gets set at the class level and cannot be easily changed, which is obviously a problem if I want people to be passing in their unique session token after they are authenticated.

Here is the flow that I am trying to implement:

  1. User submits credentials on Client app.
  2. Client app transmits credentials to API.
  3. API verifies credentials via Devise and returns an auth token.
  4. Client receives auth token and saves in session.
  5. All subsequent requests from Client include the auth token.
  6. API authenticates all requests with the included auth token.

There are many different posts on SO and Github about this. Some say that it simply cannot be done, others say that you can force it, but there are issues with threading.

How can I accomplish what I'm trying to do without losing the huge benefits that ActiveResource provides?


Solution

  • Active Resource has undergone quite an update over the past year or so and is now working well in the modern web.

    Active Resource supports the token based authentication provided by Rails through the ActionController::HttpAuthentication::Token class using custom headers.

    class Person < ActiveResource::Base
      self.headers['Authorization'] = 'Token token="abcd"'
    end
    

    You can also set any specific HTTP header using the same way. As mentioned above, headers are thread-safe, so you can set headers dynamically, even in a multi-threaded environment:

    ActiveResource::Base.headers['Authorization'] = current_session_api_token
    

    I've used an OAuth JWT strategy with Active Resource quite successfully using the second method in an API controller:

    ActiveResource::Base.headers['Authorization'] = "Bearer #{jwt.token}"