How to create a protected folder with basic auth
using Ruby on Rails
Post by Pedro Resende on the 29 of March of 2025 at 12:15
Tags: devdevelopmenttutorialrorrailsrubyRuby-On-Rails

This week, I've decided to investigate how to protect html files with basic auth on a Ruby on Rails app.
The problem is that if you store in the public/
folder it will be processed by the puma server, so, if you want to protect it, you need to use some sort of proxy.
Let's start by installing a clean Rails 8.0.2 environment for this example:
rails new protected_folder
Therefore, I've created a new folder called protected_folder
under the storage
folder.
cd protected_folder
mkdir -p storage/protected_folder
Let's install a new Gem called dotenv-rails
to load the environment variables from the .env
file.
bundle add dotenv-rails
Now, let's create a .env
file under the root folder of the project, and add the following
BASIC_AUTH_USER=user
BASIC_AUTH_PASSWORD=password
Now, let's create a new controller called protected_folder
under, app/controllers
.
rails g controller protected_folder show
if you open the file, app/controllers/protected_folder_controller.rb
, you should have the following
class ProtectedFolderController < ApplicationController
def show
end
end
Let's modify the controller to look like this
class ProtectedFolderController < ApplicationController
before_action :authenticate
protect_from_forgery except: :show
def show
requested_file = params[:path]
# Convert to a Pathname object to sanitize the path
requested_path = Pathname.new(requested_file).cleanpath.to_s
# If no file extension is present, assume it's index.html file
requested_path += "/index.html" unless requested_path.include?(".")
# Ensure the path does not escape the intended directory
safe_base = Rails.root.join("protected_storage").to_s
file_path = Rails.root.join("protected_storage", requested_path).to_s
# Ensure file_path is still inside protected_storage
if file_path.start_with?(safe_base) == false
return render plain: "401 Unauthorized", status: 401
end
if File.exist?(file_path) && !File.directory?(file_path)
send_file file_path, disposition: "inline"
else
render plain: "File not found", status: :not_found
end
end
private
def authenticate
authenticate_or_request_with_http_basic do |username, password|
username == ENV["BASIC_AUTH_USER"] && password == ENV["BASIC_AUTH_PASSWORD"]
end
end
end
finally, open the files config/routes.rb
and add the following
get "/protected_folder/*path", to: "protected_folder#show", format: false
you can now add a new file to the storage/protected_folder
folder, for example, a index.html
file.
<h1>Protected Folder</h1>
Let's finally boot up our rails app by running
rails s
Open your browser on http://localhost:3000/protected_folder/index.html
. You should have the following.

After providing the correct username and password defined in the .env
file, you should see the content of the index.html
file.
That is it, please let me know if you propose a different approach.