Using Firebase Authentication with knock for Rails

Mar 20, 2018 07:57 · 389 words · 2 minute read firebase rails ruby knock authentication

I’ve been evaluating some Authentication-as-a-Service providers recently for some side projects I have planned. My checklist has been:

  • Preferably free, low cost
  • Quick to get started with
  • Support for JWT/Token based authentication to use with an API based backend
  • No vendor lock in

Firebase Authentication checked all of these boxes for me. Unfortunately, no Admin SDK is available for Ruby to verify tokens with. I knew that the knock gem had drop in support for Auth0, so I figured it wouldn’t be too difficult to configure for Firebase. I followed the guide provided by Google on their Admin SDK page for using a third party library. Here’s what I did:

1. Get public keys from Google

These are located at https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com. You can save them as a .pem file or set them to an environment variable. Note that there may be more than one and you’ll need to decode one of your JWTs to see which kid from the JWT header matches.

2. Configure knock

Following the knock installation, once you’ve run the rails generate knock:install command, add the following to your config/initializers/knock.rb file:

# config/initializers/knock.rb

Knock.setup do |config|
  config.token_signature_algorithm = "RS256"

  cert = "..." # Load your .pem file contents or environment variable here.
  x509 = OpenSSL::X509::Certificate.new(cert)
  config.token_public_key = x509.public_key
end

3. Configure your User model

knock expects you to have a User class defined in your Rails application. To ensure that your new Firebase configuration works, you’ll also need to add the following method to your User model:

# app/models/user.rb

class User
  def self.from_token_payload payload
    self.new(payload)
    # or
    # self.find payload["sub"]
  end
end

Whatever you return from this method is what current_user will be in your controller method. You have the option of creating a user object here with the fields from the payload, or looking up the user in the database if you’re syncing your records with Firebase.

4. Make sure you’re passing your JWT with the appropriate header

knock is looking for the Authorization header and the value to be in the Bearer #{token} format. The token is available from user.getIdToken() in the firebaseui JS library. I have been using the drop in UI and session management with React available from firebaseui-web-react.

That’s it! You could also just decode the token yourself, but I think using knock saves a little bit of time and maintenance.