Using default Rails authentication with a Grape API

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.