Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A simple Sinatra app that demonstrates basic authentication
#!/user/bin/env ruby
require 'bundler/inline'
gemfile(true) do
source 'https://rubygems.org'
gem 'sinatra', '~> 1.4'
gem 'bcrypt', '~> 3.1'
end
require 'sinatra/base'
require 'bcrypt'
def hash_password(password)
BCrypt::Password.create(password).to_s
end
def test_password(password, hash)
BCrypt::Password.new(hash) == password
end
User = Struct.new(:id, :username, :password_hash)
USERS = [
User.new(1, 'bob', hash_password('the builder')),
User.new(2, 'sally', hash_password('go round the sun')),
]
class AuthExample < Sinatra::Base
enable :inline_templates
enable :sessions
get '/' do
if current_user
erb :home
else
redirect '/sign_in'
end
end
get '/sign_in' do
erb :sign_in
end
post '/sign_in' do
user = USERS.find { |u| u.username == params[:username] }
if user && test_password(params[:password], user.password_hash)
session.clear
session[:user_id] = user.id
redirect '/'
else
@error = 'Username or password was incorrect'
erb :sign_in
end
end
post '/create_user' do
USERS << User.new(
USERS.size + 1, #id
params[:username], #username
hash_password(params[:password]) #password_hash
)
redirect '/'
end
post '/sign_out' do
session.clear
redirect '/sign_in'
end
helpers do
def current_user
if session[:user_id]
USERS.find { |u| u.id == session[:user_id] }
else
nil
end
end
end
run!
end
__END__
@@ sign_in
<h1>Sign in</h1>
<% if @error %>
<p class="error"><%= @error %></p>
<% end %>
<form action="/sign_in" method="POST">
<input name="username" placeholder="Username" />
<input name="password" type="password" placeholder="Password" />
<input type="submit" value="Sign In" />
</form>
@@ home
<h1>Home</h1>
<p>Hello, <%= current_user.username %>.</p>
<form action="/sign_out" method="POST">
<input type="submit" value="Sign Out" />
</form>
<p>There are <%= USERS.size %> users registered:</p>
<ul>
<% USERS.each do |user| %>
<li><%= user.username %></li>
<% end %>
</ul>
<h2>Create New User</h2>
<form action="/create_user" method="POST">
<input name="username" placeholder="Username" />
<input name="password" placeholder="Password" />
<input type="submit" value="Create User" />
</form>
@@ layout
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Simple Authentication Example</title>
<style>
input { display: block; }
.error { color: red; }
</style>
</head>
<body><%= yield %></body>
</html>
@CodeMonkeySteve

This comment has been minimized.

Copy link

CodeMonkeySteve commented May 24, 2016

The string comparison on line 18 leaves you vulnerable to timing attacks, you need a constant-time comparison function (e.g. https://github.com/plataformatec/devise/blob/9a11586a724487dc98dddea0ab9c8afcc0e9439d/lib/devise.rb#L484)

@tomdalling

This comment has been minimized.

Copy link
Owner Author

tomdalling commented May 24, 2016

@CodeMonkeySteve but it's not a plain text string comparison, is it? codahale/bcrypt-ruby#42

@christiangenco

This comment has been minimized.

Copy link

christiangenco commented Aug 11, 2016

Shouldn't you be salting the passwords?

@kathgironpe

This comment has been minimized.

Copy link

kathgironpe commented Sep 8, 2016

I think this is only good for apps that only require 1 user or much smaller.
I only use http basic authentication for such cases.

@tomdalling

This comment has been minimized.

Copy link
Owner Author

tomdalling commented Nov 20, 2016

@christiangenco Salting is done automatically inside bcrypt. Also sorry for the late reply – GitHub didn't notify me.

@flips

This comment has been minimized.

Copy link

flips commented Mar 11, 2017

Thanks @tomdalling for the example. Helped me realize what I was doing wrong. 🙂

@katgironpe Care to elaborate why the basic principle showed here in your opinion wouldn't scale/be safe in bigger setups? (What would you recommend for bigger setups?)

@philiprhoades

This comment has been minimized.

Copy link

philiprhoades commented Jun 17, 2018

There is a typo after the HashBang: "/user . . "

@w3b-net-au

This comment has been minimized.

Copy link

w3b-net-au commented Apr 23, 2020

Nice demo, thanks. Still works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.