Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sinatra - API - Authentication

We going to develop a little API application in Sinatra. What are the authentication options available to secure the API calls?

like image 477
Saim Avatar asked Aug 13 '10 18:08

Saim


2 Answers

Sinatra has no built-in authentication support. There are some gems available, but most are designed for user authentication (i.e. for a website). For an API, they seem like overkill. It’s easy enough to make your own. Simply check the request params in each of your routes to see if they contain a valid API key, and if not, return a 401 error.

helpers do   def valid_key? (key)     false   end end  get "/" do   error 401 unless valid_key?(params[:key])    "Hello, world." end  #  $ irb -r open-uri #  >> open("http://yourapp.com/api/?key=123") #  OpenURI::HTTPError: 401 Unauthorized 

Nothing after the call to error will happen if your valid_key? method returns false — error calls halt internally, which stops the request from continuing.

Of course, it’s not ideal to repeat the check at the beginning of each route. Instead, you can create a small extension that adds conditions to your routes:

class App < Sinatra::Base   register do     def check (name)       condition do         error 401 unless send(name) == true       end     end   end    helpers do     def valid_key?       params[:key].to_i % 2 > 0     end   end    get "/", :check => :valid_key? do     [1, 2, 3].to_json   end end 

If you just want authentication on all your routes, use a before handler:

before do   error 401 unless params[:key] =~ /^xyz/ end  get "/" do   {"e" => mc**2}.to_json end 
like image 69
Todd Yandell Avatar answered Sep 17 '22 19:09

Todd Yandell


http://www.secondforge.com/blog/2014/11/05/simple-api-authentication-in-sinatra/ has a slightly more detailed answer that uses user tokens.

This is one step more complicated than an API key, but is necessary if your API needs authentication to log in a user to do things such as editing a name/email/password, or accessing per-user information. (i.e. "private" API actions). You can also revoke/expire user tokens to let people log out, etc.

class App < Sinatra::Base    before do     begin       if request.body.read(1)         request.body.rewind         @request_payload = JSON.parse request.body.read, { symbolize_names: true }       end     rescue JSON::ParserError => e       request.body.rewind       puts "The body #{request.body.read} was not JSON"     end   end    post '/login' do     params = @request_payload[:user]      user = User.find(email: params[:email])     if user.password == params[:password] #compare the hash to the string; magic       #log the user in     else       #tell the user they aren't logged in     end   end end 

(It's worth to note that it's more common to read credentials from an HTTP header instead of the JSON body, but the author mentions that.)

like image 28
chug2k Avatar answered Sep 20 '22 19:09

chug2k