Recently, I needed to write an API to work with an iPhone application. I used Clearance for authentication. Unfortunately, it doesn’t support HTTP Basic Authentication out of the box, which made it difficult to use in an API.

I found this issue with a patch that worked. However, the Thoughtbot guys said that Rack::Auth::Basic should be used instead. No examples were provided.

I tried for a few days to get things to work with Rack and ended up using that patch.

Today I decided to take another look at this. I found a cached slideshow on Google that had the info I needed to make an API using a Sinatra app as a Rails Metal.

This is basically how I got HTTP Basic Auth working with Clearance:

# Put this in app/metals/api.rb
require 'sinatra/base'

class Api < Sinatra::Base

  before do
    content_type :json
    authenticate if api_request?
  end

  helpers do
    def api_request?
      request.path_info.match %r{/api/}i
    end

    def authenticate
      unless authenticated?
        response['WWW-Authenticate'] = %(Basic realm="My API")
        throw(:halt, [401, "Unauthorized\n"])
      end
    end

    def authenticated?
      auth = Rack::Auth::Basic::Request.new(request.env)
      auth.provided? && auth.basic? &&
        auth.credentials && @current_user = User.authenticate(*auth.credentials)
    end

    def current_user
      @current_user
    end
  end

  get '/api/account.json' do
    current_user.to_json
  end
end

Hope it helps someone else having this problem.