-
-
Save midnight-wonderer/c40b8c46dc42cb560ccbdcd4a79f52c9 to your computer and use it in GitHub Desktop.
FirebaseAuth::Auth.verify_id_token | Ruby solution for https://firebase.google.com/docs/auth/admin/verify-id-tokens
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Usage: | |
# ======== | |
# FirebaseAuth::Auth.verify_id_token(your_id_token) | |
# | |
# The method call follows the same API of the Node.js, JAVA and Python SDKs. | |
# See https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_the_firebase_admin_sdk | |
# Dependencies: | |
# --------------- | |
# gem 'activesupport' | |
# gem 'faraday' | |
# gem 'jwt', '~> 1.5', '>= 1.5.6' | |
# require 'jwt' | |
# require 'faraday' | |
# require 'active_support/core_ext/module/delegation' | |
# | |
# require 'openssl' | |
# require 'singleton' | |
# require 'ostruct' | |
module FirebaseAuth | |
class PublicKeys | |
URL = 'https://www.googleapis.com/robot/v1/metadata/x509/[email protected]' | |
EXPIRES_HEADER = 'expires' | |
attr_reader :response | |
delegate :keys, :values, to: :data | |
def initialize | |
@response = fetch | |
end | |
def valid? | |
Time.now.utc < time_to_expire | |
end | |
def data | |
@parsed_body ||= JSON.parse(response.body) | |
end | |
def look_up(kid) | |
@certificate_hash ||= Hash[data.map { |k, v| [k, OpenSSL::X509::Certificate.new(v)] }] | |
@certificate_hash[kid] | |
end | |
private | |
def time_to_expire | |
@time_to_expire ||= Time.parse( | |
response.headers[EXPIRES_HEADER] | |
) | |
end | |
def fetch | |
Faraday.get(URL) | |
end | |
end | |
class IDTokenVerifier | |
JWT_OPTIONS = { algorithm: 'RS256', verify_iat: true } | |
def initialize(public_keys) | |
@public_keys = public_keys | |
end | |
def verify(id_token) | |
kid = JWT.decode(id_token, nil, false).last['kid'] rescue nil | |
decode_jwt(id_token, @public_keys.look_up(kid)) | |
end | |
private | |
def decode_jwt(id_token, x509) | |
JWT.decode(id_token, x509.public_key, true, JWT_OPTIONS) | |
rescue JWT::VerificationError | |
nil | |
end | |
end | |
class Auth | |
include Singleton | |
def initialize | |
refresh | |
end | |
def public_keys | |
resolve { @public_keys } | |
end | |
def verify_id_token(id_token) | |
result = resolve { @id_token_verifier.verify(id_token) } | |
if result | |
payload, header = result | |
[OpenStruct.new(payload), OpenStruct.new(header)] | |
end | |
end | |
class << self | |
delegate :verify_id_token, :public_keys, to: :instance | |
end | |
private | |
def refresh | |
@public_keys = PublicKeys.new | |
@id_token_verifier = IDTokenVerifier.new(@public_keys) | |
end | |
def resolve | |
refresh unless @public_keys.valid? | |
yield | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@JeffreyCheng92 sorry I did not see your comment.
It is way too late now but in order to integrate the snippet into Rails project you can use
https://apidock.com/rails/v4.2.7/ActionController/HttpAuthentication/Token/token_and_options
to retrieve the authorization header.
and this is an example of tokens returned from Firebase