38

Hi I'm from Grails background and new to Rails. I wish to do http basic authentication in rails.

I have a code in grails which does basic authentication like this:

def authString = "${key}:".getBytes().encodeBase64().toString()
def conn = "http://something.net".toURL().openConnection()
conn.setRequestProperty("Authorization", "Basic ${authString}")

Can the same be done with rails?

Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
sriram
  • 8,562
  • 19
  • 63
  • 82

9 Answers9

96

Write the below code, in the controller which you want to restrict using http basic authentication

class ApplicationController < ActionController::Base
  http_basic_authenticate_with :name => "user", :password => "password" 
end

Making a request with open-uri would look like this:

require 'open-uri'

open("http://www.your-website.net/", 
  http_basic_authentication: ["user", "password"])
Blair Anderson
  • 19,463
  • 8
  • 77
  • 114
Nishant
  • 2,975
  • 23
  • 38
22

In Ruby on Rails 4 you can easily apply basic HTTP Authentication site wide or per controller depending on the context.

For example, if you need site wide authentication:

class ApplicationController < ActionController::Base
  http_basic_authenticate_with name: "admin", password: "hunter2"
end

Or on a per controller basis:

class CarsController < ApplicationController
  http_basic_authenticate_with name: "admin", password: "hunter2"
end
sergserg
  • 21,716
  • 41
  • 129
  • 182
12

I upvoted @Nishant's answer but wanted to add another tidbit. You can always set filters so it only applies to certain controller actions by passing only or except like so:

http_basic_authenticate_with name: "admin", password: "strongpasswordhere", only: [:admin, :new, :edit, :destroy]

or

http_basic_authenticate_with name: "admin", password: "strongpasswordhere", except: [:show]

Very helpful in many instances.

Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
Kyle Carlson
  • 7,967
  • 5
  • 35
  • 43
8
# app/controllers/application_controller.rb
  before_filter :http_basic_auth

  def http_basic_auth
    if ENV['HTTP_AUTH'] =~ %r{(.+)\:(.+)}
      unless authenticate_with_http_basic { |user, password|  user == $1 && password == $2 }
        request_http_basic_authentication
      end
    end
  end

and then you just need to export your environment variable with the user:password for example:

   export HTTP_AUTH=user:pass

if you are using heroku.com:

   heroku config:set HTTP_AUTH=user:pass
Heriberto Magaña
  • 882
  • 10
  • 11
2

There is a great Rails Cast on this topic

http://railscasts.com/episodes/82-http-basic-authentication

Kansha
  • 570
  • 4
  • 12
2

When connecting to HTTP endpoints protected by basic HTTP authentication I usually use HTTParty. HTTParty is simple wrapper for lower Ruby STD classes like net/http.

Example usage of HTTParty with basic auth.

class Delicious
  include HTTParty
  base_uri 'https://api.del.icio.us/v1'

  def initialize(u, p)
    @auth = {username: u, password: p}
  end

  def recent options={}
    options.merge!({basic_auth: @auth})
    self.class.get('/posts/recent', options)
  end
end

delicious = Delicious.new("<username>", "<password>")

pp delicious.recent #=> list of recent elements

Check for more examples on GitHub.

Oto Brglez
  • 4,113
  • 1
  • 26
  • 33
2

Above answers are correct, but it is better to not put the user and password in the source code.

Better have the password in environment variables for production (in the code is OK for development)

class YourController..
  http_basic_authenticate_with name: ENV["HTTP_BASIC_AUTH_USER"], password: ENV["HTTP_BASIC_AUTH_PASSWORD"], if: -> { ENV['RAILS_ENV'] == 'production' }
  http_basic_authenticate_with name: "user", password: "pass", if: -> { ENV['RAILS_ENV'] != 'production' }
dowi
  • 1,005
  • 15
  • 30
1

For the latest rails version there is a ASCIIcast that explains with steps the HTTP Basic Authentication.

The link goes here.

Side Note: Be warned that HTTP Basic Authentication transmits the username and password in clear text, so you should not use this method for applications where a higher level of security is required.

sjain
  • 23,126
  • 28
  • 107
  • 185
  • 2
    If you request to a website with HTTP Basic Authentication using an `https` url the headers will still be encrypted though right? – Kelsey Hannan Dec 02 '19 at 21:16
0

You can use request.basic_auth to pass basic auth parameters required for authentication. content_type can be changed according to the requirement.

You will have to include -

require 'net/http'
require 'uri'

Request code will look like this -

  key = "awknfkjn93013nksdkjnsd09920930jwkslkd102"
  token = "qs90si90w4jm309w0kd5009kdw700i29012dfmk"
  uri = URI("http://something.net")
  request = Net::HTTP::Post.new(uri)
  request.content_type = 'application/x-www-form-urlencoded'
  request.basic_auth(key, token)
  payload = {
              your_payload_key=> "your_payload_value"
            }
  request.set_form_data(payload)
  request_options = {
      use_ssl: uri.scheme == "https"
  }
  response = Net::HTTP.start(uri.hostname, uri.port, request_options) do |http|
    http.request(request)
  end
Vivek Kumar
  • 2,625
  • 2
  • 25
  • 33