class FirebaseIDToken::Validator
Constants
- FIREBASE_CERTS_EXPIRY
- FIREBASE_CERTS_URI
- FIREBASE_ISSUERS_PREFIX
Public Class Methods
new(keyopts = {})
click to toggle source
# File lib/firebase-id-token.rb, line 46 def initialize(keyopts = {}) if keyopts[:x509_cert] @certs_mode = :literal @certs = { :_ => keyopts[:x509_cert] } # elsif keyopts[:jwk_uri] # TODO # @certs_mode = :jwk # @certs = {} else @certs_mode = :old_skool @certs = {} end @certs_expiry = keyopts.fetch(:expiry, FIREBASE_CERTS_EXPIRY) end
Public Instance Methods
check(token, aud)
click to toggle source
If it validates, returns a hash with the JWT payload from the ID Token.
You have to provide an "aud" value, which must match the token's field with that name. Furthermore the tokens field "iss" must be "https://securetoken.google.com/<aud>"
If something fails, raises an error
@param [String] token
The string form of the token
@param [String] aud
The required audience value
@return [Hash] The decoded ID token
# File lib/firebase-id-token.rb, line 76 def check(token, aud) payload = check_cached_certs(token, aud) unless payload # no certs worked, might've expired, refresh if refresh_certs payload = check_cached_certs(token, aud) unless payload raise SignatureError, 'Token not verified as issued by Firebase' end else raise CertificateError, 'Unable to retrieve Firebase public keys' end end payload end
Private Instance Methods
certs_cache_expired?()
click to toggle source
# File lib/firebase-id-token.rb, line 162 def certs_cache_expired? if defined? @certs_last_refresh Time.now > @certs_last_refresh + @certs_expiry else true end end
check_cached_certs(token, aud)
click to toggle source
tries to validate the token against each cached cert. Returns the token payload or raises a ValidationError
or
nil, which means none of the certs validated.
# File lib/firebase-id-token.rb, line 100 def check_cached_certs(token, aud) payload = nil # find first public key that validates this token @certs.detect do |key, cert| begin public_key = cert.public_key decoded_token = JWT.decode(token, public_key, true, { :algorithm => 'RS256' }) payload = decoded_token.first payload rescue JWT::ExpiredSignature raise ExpiredTokenError, 'Token signature is expired' rescue JWT::DecodeError => e nil # go on, try the next cert end end if payload if !(payload.has_key?('aud') && payload['aud'] == aud) raise AudienceMismatchError, 'Token audience mismatch' end if FIREBASE_ISSUERS_PREFIX + aud != payload['iss'] raise InvalidIssuerError, 'Token issuer mismatch' end payload else nil end end
old_skool_refresh_certs()
click to toggle source
# File lib/firebase-id-token.rb, line 141 def old_skool_refresh_certs return true unless certs_cache_expired? uri = URI(FIREBASE_CERTS_URI) get = Net::HTTP::Get.new uri.request_uri http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true res = http.request(get) if res.is_a?(Net::HTTPSuccess) new_certs = Hash[MultiJson.load(res.body).map do |key, cert| [key, OpenSSL::X509::Certificate.new(cert)] end] @certs.merge! new_certs @certs_last_refresh = Time.now true else false end end
refresh_certs()
click to toggle source
returns false if there was a problem
# File lib/firebase-id-token.rb, line 132 def refresh_certs case @certs_mode when :literal true # no-op when :old_skool old_skool_refresh_certs end end