Code Monkey home page Code Monkey logo

firebase_id_token's Introduction

Ruby Firebase ID Token verifier (pre-release)

Alt text Code Climate Issue Count Test Coverage Inline docs

A Ruby gem to verify the signature of Firebase ID Tokens. It uses Redis to store Google's x509 certificates and manage their expiration time, so you don't need to request Google's API in every execution and can access it as fast as reading from memory.

It also checks the JWT payload parameters as recommended here by Firebase official documentation.

Feel free to open any issue or to contact me directly.
Any contribution is welcome.

Docs

Requirements

  • Redis

Installing

gem install firebase_id_token

or in your Gemfile

gem 'firebase_id_token', '~> 2.5.1'

then

bundle install

Configuration

It's needed to set up your Firebase Project ID.

If you are using Rails, this should probably go into config/initializers/firebase_id_token.rb.

FirebaseIdToken.configure do |config|
  config.project_ids = ['your-firebase-project-id']
end

project_ids must be a Array.

If you want to verify signatures from more than one Firebase project, just add more Project IDs to the list.

You can also pass a Redis instance to config if you are not using Redis defaults.
In this case, you must have the gem redis in your Gemfile.

FirebaseIdToken.configure do |config|
  config.project_ids = ['your-firebase-project-id']
  config.redis = Redis.new(host: '10.0.1.1', port: 6380, db: 15)
end

Otherwise, it will use just Redis.new as the instance.

Usage

You can get a glimpse of it by reading our RSpec output on your machine. It's really helpful. But here is a complete guide:

Downloading Certificates

Before verifying tokens, you need to download Google's x509 certificates.

To do it simply:

FirebaseIdToken::Certificates.request

It will download the certificates and save it in Redis, but only if Redis certificates database is empty. To force download and override Redis database, use:

FirebaseIdToken::Certificates.request!

Google give us information about the certificates expiration time, it's used to set a Redis TTL (Time-To-Live) when saving it. By doing so, the certificates will be automatically deleted after its expiration.

Certificates Info

Checks the presence of certificates in Redis database.

FirebaseIdToken::Certificates.present?
=> true

How many seconds until the certificate's expiration.

FirebaseIdToken::Certificates.ttl
=> 22352

Lists all certificates in a database.

FirebaseIdToken::Certificates.all
=> [{"ec8f292sd30224afac5c55540df66d1f999d" => <OpenSSL::X509::Certificate: [...]]

Finds the respective certificate of a given Key ID.

FirebaseIdToken::Certificates.find('ec8f292sd30224afac5c55540df66d1f999d')
=> <OpenSSL::X509::Certificate: subject=<OpenSSL::X509 [...]>

Downloading in Rails

If you are using Rails, it's clever to download certificates in a cron task, you can use whenever.

Example

Read whenever's guide on how to set it up.

Create your task in lib/tasks/firebase.rake:

namespace :firebase do
  namespace :certificates do
    desc "Request Google's x509 certificates when Redis is empty"
    task request: :environment do
      FirebaseIdToken::Certificates.request
    end

    desc "Request Google's x509 certificates and override Redis"
    task force_request: :environment do
      FirebaseIdToken::Certificates.request!
    end
  end
end

And in your config/schedule.rb you might have:

every 1.hour do
  rake 'firebase:certificates:force_request'
end

Then:

$ whenever --update-crontab

I recommend running it once every hour or every 30 minutes, it's up to you. Normally the certificates expiration time is around 4 to 6 hours, but it's good to perform it in a small fraction of this time.

When developing, you should just run the task:

$ rake firebase:certificates:request

And remember, you need the Redis server to be running.

Verifying Tokens

Pass the Firebase ID Token to FirebaseIdToken::Signature.verify and it will return the token payload if everything is ok:

FirebaseIdToken::Signature.verify(token)
=> {"iss"=>"https://securetoken.google.com/firebase-id-token", "name"=>"Bob Test", [...]}

When either the signature is false or the token is invalid, it will return nil:

FirebaseIdToken::Signature.verify(fake_token)
=> nil

FirebaseIdToken::Signature.verify('aaaaaa')
=> nil

WARNING: If you try to verify a signature without any certificates in Redis database it will raise a FirebaseIdToken::Exceptions::NoCertificatesError.

Payload Structure

In case you need, here's a example of the payload structure from a Google login in JSON.

{  
   "iss":"https://securetoken.google.com/firebase-id-token",
   "name":"Ugly Bob",
   "picture":"https://someurl.com/photo.jpg",
   "aud":"firebase-id-token",
   "auth_time":1492981192,
   "user_id":"theUserID",
   "sub":"theUserID",
   "iat":1492981200,
   "exp":33029000017,
   "email":"[email protected]",
   "email_verified":true,
   "firebase":{  
      "identities":{  
         "google.com":[  
            "1010101010101010101"
         ],
         "email":[  
            "[email protected]"
         ]
      },
      "sign_in_provider":"google.com"
   }
}

Development

The test suite can be run with bundle exec rake rspec

The test mode is prepared as preparation for the test.

FirebaseIdToken.test!

By using test mode, the following methods become available.

# RSA PRIVATE KEY
FirebaseIdToken::Testing::Certificates.private_key
# CERTIFICATE
FirebaseIdToken::Testing::Certificates.certificate

CERTIFICATE will always return the same value and will not communicate to google.

Example

Rails test

Describe the following in test_helper.rb etc.

  • test_helper
class ActiveSupport::TestCase
  setup do
    FirebaseIdToken.test!
  end
end
  • controller_test
require 'test_helper'

module Api
  module V1
    module UsersControllerTest < ActionController::TestCase
      setup do
        @routes = Engine.routes
        @user = users(:one)
      end
        
      def create_token(sub: nil)
        _payload = payload.merge({sub: sub})
        JWT.encode _payload, OpenSSL::PKey::RSA.new(FirebaseIdToken::Testing::Certificates.private_key), 'RS256'
      end

      def payload
        # payload.json
      end

      test 'should success get api v1 users ' do
        get :show, headers: create_token(@user.id)
        assert_response :success
      end
    end
  end
end

License

The gem is available as open source under the terms of the MIT License.

firebase_id_token's People

Contributors

ababich avatar arkhwise avatar dps avatar fschuindt avatar guilhermefeitoza-id avatar metekabak avatar penguinwokrs avatar socio-mehmet avatar thornomad avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.