Adding Basic HTTP Authentication to Rails Routes in Plain Ruby on Rails
In this article, we will look at implementing basic HTTP authentication in Ruby on Rails using constraints in Rails routes. This is useful for admin panels and other similar functionality where you want to restrict access to a specific group of users. Let's dive in.
Understanding Basic HTTP Authentication
Basic HTTP Authentication is a security technique in which a user agent passes a username and password to the server as part of an HTTP request. This information is base64-encoded, but not encrypted, making it suitable for simple authentication cases where traffic is served over HTTPS.
Setting up your private routes
The first step is to define your route for example within a namespaced admin
section. This is where we'll set up our protected routes.
# routes.rb
namespace :admin, path: '/panel_admin' do
root to: 'base#index'
constraints AdminConstraint do
mount GrapeSwaggerRails::Engine, at: '/docs'
mount MissionControl::Jobs::Engine, at: '/jobs'
get 'protected', to: 'protected#index'
end
# redirect to login from any path when unauthorized
get '*path', to: redirect('/panel_admin')
end
Any unauthorized requests will be redirected back to the /panel_admin
front page, because the rest are under AdminConstraint
block blocked by our custom logic.
Creating the AdminConstraint
The AdminConstraint
class checks that the request matches the correct HTTP Authentication. Here's how you set it up:
# config/initializers/admin_constraint.rb
class AdminConstraint
def self.matches?(request)
return request.env["HTTP_AUTHORIZATION"] == "Basic " + Base64.strict_encode64("#{ENV['ADMIN_LOGIN']}:#{ENV['ADMIN_PASSWORD']}")
end
end
In our method matches?
, we are comparing the incoming request's HTTP_AUTHORIZATION
header to the Basic Auth format, which is 'Basic base64_encoded_credentials'. Please make sure you have your ENVs filled properly
#.env
# add long and complicated login and password
ADMIN_LOGIN=abcd
ADMIN_PASSWORd=abcd
Setting Up the Admin Controller
In your admin controller, call http_basic_authenticate_with
at the beginning of the code block. This triggers the authentication mechanism.
class Admin::BaseController < ApplicationController
http_basic_authenticate_with name: ENV['ADMIN_LOGIN'], password: ENV['ADMIN_PASSWORD']
def index
render plain: "Hello!"
end
end
The http_basic_authenticate_with
method takes arguments of the username and password required for access. When we will go to that page and you will type login and password correctly, then your browser will fill the header HTTP_AUTHORIZATION
with that login and password. So then you can easily go to our restricted page from constraint block, because our AdminConstraint
will return true
.
Ensuring security
Finally, remember to use HTTPS
as base64 is visible on the network. To protect against brute-force attacks, consider setting up your firewall or rack_attack
for security to ban a user after a few failed attempts to call /panel_admin
. Of course if possible, please use standard token auth authorization for your restricted controllers.
Happy restricting your routes!