Skip to content

Instantly share code, notes, and snippets.

@clody69

clody69/server.rb

Last active Dec 15, 2015
Embed
What would you like to do?
Password-less Authentication by email. Inspired by some of Luke's writings on login and password usability issues (http://www.lukew.com/ff/entry.asp?1487, http://alistapart.com/article/signupforms), I have decided to test an authentication mechanism without passwords. In simple terms this can be seen as a combination of the "remember me" and "fo…
require 'sinatra'
require 'haml'
$users = {'john' => {:roles => [:user] }, 'mike' => {:roles => [:user, :admin] } }
$tokens = {'123' => {:username => 'john', :expires_at => Time.now+60}}
helpers do
def authenticate_user!
@auth_token = auth_token
if $tokens.has_key?(@auth_token) && !$tokens[@auth_token][:expires_at].nil? && $tokens[@auth_token][:expires_at] > Time.now
@current_user = $tokens[@auth_token][:username]
else
@current_user = nil
end
end
def current_user
@current_user
end
def login?
!@current_user.nil?
end
def activate!(token)
if $tokens.has_key?(token) && $tokens[token][:expires_at].nil?
$tokens[token][:expires_at] = Time.now + 600
return true
end
end
def logout
$tokens.delete(@auth_token)
end
def roles?(roles)
return true if roles.include?(:any)
!(roles & $users[@current_user][:roles]).empty?
end
def auth_token
if params.has_key?("auth_token")
return params["auth_token"]
elsif request.env.has_key?('HTTP_AUTHENTICATION')
return request.env["HTTP_AUTHENTICATION"][/Token token="?(\w+)"?/,1]
end
end
def generate_auth_token
begin
token = SecureRandom.hex(20)
end while $tokens.has_key?(token)
token
end
end
set(:auth) do |*roles|
condition do
halt 401, 'Unauthorized' unless login?
halt 403, 'Forbidden' unless roles?(roles.to_a)
end
end
before do
authenticate_user!
end
get '/' do
haml :index
end
get "/resource", :auth => [:user, :admin] do
"You can access the resource for authorized users"
end
get "/secret", :auth => [:admin] do
"You can accesss the resource only for admins"
end
get "/login" do
haml :login
end
get "/logout", :auth => [:any] do
logout
haml :logout
end
post "/login" do
haml :not_authorized unless $users.include?(params[:email])
@token = generate_auth_token
$tokens[@token] = {:username => params[:email], :expires_at => nil}
haml :authentication_email
end
get "/activate/:token" do
@token = params[:token]
if activate!(params[:token])
haml :authenticated
else
haml :not_authenticated
end
end
__END__
@@layout
!!! 5
%html
%head
%title Sinatra Instant Email Authentication
%body
=yield
@@index
:javascript
fetch = function(url,id) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.setRequestHeader('Authentication', 'Token token=' + localStorage.getItem('auth_token') );
xhr.onload = function(e) {
document.getElementById(id).innerHTML = (this.status == 200) ? this.responseText : this.status + ' ' + this.statusText;
};
xhr.send();
}
logout = function() {
window.location.href = "/logout?auth_token=" + localStorage.getItem('auth_token');
}
fetch('/resource', 'resource');
fetch('/secret', 'secret');
%a(href="/login") Login
%a(href="#" onclick="logout();" ) Logout
%p
XHR Repsonse on authorized users:
%span#resource
%p
XHR Response on a secret resource only for admin:
%span#secret
@@login
%form(action="/login" method="post")
%div
%label(for="email")Enter your email:
%input#email(type="text" name="email")
%div
%input(type="submit" value="Login")
@@authentication_email
:javascript
localStorage.setItem('auth_token', '#{@token}');
%p Here is your email for authenticating.
%p In order to login into the system, please follow this link:
%a(href="/activate/#{@token}") Log me in
@@logout
:javascript
localStorage.removeItem('auth_token');
%p You have logged out
%a(href="/") Home
@@authenticated
%p
You have logged in and now you can access your
%a(href="/") home
@@not_authenticated
%p
You activation failed.
@@not_authorized
%p You are not authorized.
@burningTyger

This comment has been minimized.

Copy link

@burningTyger burningTyger commented Nov 21, 2014

Nice, been looking for this. Seems simple enough and I might adapt it to my needs so it can replace a silly full fledged auth system.

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.