Using default Rails authentication with a Grape API
Recently, I was working on a Chrome extension for a web app where I wanted to share the login state between the extension and the web app.
Generally you'd roll with a token-based authentication system or relying on API keys, but neither of those approaches are acceptable if you want to roll out something real quick.
(Sidenote: There's a lot of hype around "stateless" authentication these days, but 1. you likely don't need it, and 2. If you want to be able to revoke a token, say if it gets leaked, you will need to maintain a blacklist, which is, guess what - state.)
To integrate our Grape API with the default cookie/session-based Rails authentication system, we will be using Warden. It is a really nice drop-in authentication middleware which doesn't change your application in any way unless you explicitly do so, and if you're using Devise, you're already using Warden.
We will basically be implementing a Grape helper method to take care of this. This is what my directory structure looks like:
app/controllers/api
├── base.rb
└── v1
├── base.rb
├── lists.rb
├── defaults.rb
└── helpers.rb
Inside of helpers.rb
is where we'll be defining the authentication helper.
module API
module V1
module Helpers
extend Grape::API::Helpers
def current_user
warden = env["warden"]
@current_user ||= warden.authenticate
end
end
end
end
Inside my defaults.rb
I added the following code:
helpers API::V1::Helpers
But you could add it inside base.rb
as well.
Inside of all the files where I'm defining API resources, I include the following code:
module API
module V1
class Lists < Grape::API
include API::V1::Defaults
end
end
end
And then inside of any route I can simply access current_user
, and as long as the API request included the Rails session cookie, current_user
will be set to the correct user.