How To: Simple Firebase REST API server authentication using Ruby

Published 02 December 2016 under software, firebase, real-time database, rubyonrails

Firebase is a set of tools and infrastructure which includes a real-time database. We recently needed to get a Ruby on Rails application talking to a Firebase real-time database over their REST API. Unfortunately, the documentation is somewhat scarce on how to do get authentication to work without using the deprecated auth parameter. The new way seems to be to send an access_token parameter or Authorization header as part of the request to the API. We are generating the access token using the following:

require 'jwt'  

credentials = JSON.parse(File.read("credentials.json"))
private_key = OpenSSL::PKey::RSA.new credentials["private_key"]

def generate_jwt_assertion
  now_seconds = Time.now.to_i
  payload = {:iss => credentials["client_email"],
             :aud => credentials["token_uri"],
             :iat => now_seconds,
             :exp => now_seconds+(60*60), # Maximum expiration time is one hour
             :scope => 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/firebase.database'
  }
  JWT.encode payload, private_key, "RS256"
end

def generate_access_token
  uri = URI.parse(credentials["token_uri"])
  https = Net::HTTP.new(uri.host, uri.port)
  https.use_ssl = true
  req = Net::HTTP::Post.new(uri.path)
  req['Cache-Control'] = "no-store"
  req.set_form_data({
    grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
    assertion: generate_jwt_assertion
  })

  resp = JSON.parse(https.request(req).body)
  resp["access_token"]
end

credentials.json is the file we got from Project settings -> Service Accounts, GENERATE NEW PRIVATE KEY. It's also worth noting we're using the ruby jwt gem to generate the JSON web token for the assertion. This can be installed using gem install jwt.

The result from generate_access_token can then be passed either as a header or a GET parameter in our request to the API. For example, using the Authorization header in a POST request:

  def post(path, data)
    uri = URI.parse("https://#{credentials["project_id"]}.firebaseio.com/#{path}.json")
    https = Net::HTTP.new(uri.host, uri.port)
    https.use_ssl = true
    req = Net::HTTP::Post.new(uri.path)
    req["Authorization"] = "Bearer #{Firebase.get_access_token}"
    req.body = data.to_json
    return https.request(req)
  end 

 

 

Comments

blog comments powered by Disqus