API authentication in Sinatra with Clearance or Authlogic
I needed HTTP basic authentication for a Sinatra app running as a Rails Metal. I have two apps, one running Clearance and another running Authlogic.
Using the info from my previous post I wrote a small Sinatra plugin that works with both Clearance and Authlogic.
module MyApp
module Sinatra
module Authentication
def self.registered(app)
app.before do
content_type :json
authenticate if api_request?
end
app.helpers Helpers
end
module Helpers
def api_request?
request.path_info.match %r{^/api/}i
end
def authenticate
unless authenticated?
response['WWW-Authenticate'] = %(Basic realm="API")
throw(:halt, error('Unauthorized', 401))
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
def render(output, code = 200)
out = { :response => output }.to_json + "\n"
[code.to_i, out]
end
def error(output = 'ERROR', code = 400)
render(output, code)
end
end
end
end
end
Trow the file above in lib/sinatra_authentication.rb
. Then, your metal,
app/metals/api.rb
would look something like this:
require 'sinatra_authentication'
class Api < Sinatra::Base
register ::MyApp::Sinatra::Authentication
get '/api/ping' do
render "Authentication successful"
end
end
Authlogic doesn’t have an authenticate
method, so I added this to
app/models/user.rb
:
class User < ActiveRecord::Base
acts_as_authentic
def self.authenticate(username, password)
c = find_by_username(username)
c && c.valid_password?(password) ? c : nil
end
end
Hope it helps someone else.