module Firebase::Authentication
Constants
- ALGORITHM
- CLIENT_CERT_URL
- ISSUER_BASE_URL
- VERSION
Public Class Methods
create_custom_token(uid, claims = {})
click to toggle source
# File lib/firebase/authentication.rb, line 36 def create_custom_token(uid, claims = {}) private_key = OpenSSL::PKey::RSA.new Global.firebase.private_key.gsub("\\n", "\n") service_account_email = Global.firebase.client_email now_seconds = Time.now.to_i payload = { iss: service_account_email, sub: service_account_email, aud: "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit", iat: now_seconds, exp: now_seconds + (60 * 60), uid: uid, claims: claims } JWT.encode payload, private_key, "RS256" end
verify(token)
click to toggle source
# File lib/firebase/authentication.rb, line 11 def verify(token) Rails.logger.info "#{self.class.name}\##{__method__} called." Rails.logger.info token raise "id token must be a String" unless token.is_a?(String) full_decoded_token = _decode_token(token) err_msg = _validate_jwt(full_decoded_token) raise err_msg if err_msg public_key = _fetch_public_keys[full_decoded_token[:header]["kid"]] unless public_key raise 'Firebase ID token has "kid" claim which does not correspond to a known public key.'\ "Most likely the ID token is expired, so get a fresh token from your client app and try again." end certificate = OpenSSL::X509::Certificate.new(public_key) decoded_token = _decode_token(token, certificate.public_key, verify: true, options: { algorithm: ALGORITHM, verify_iat: true }) { "uid" => decoded_token[:payload]["sub"], "decoded_token" => decoded_token } end
Private Class Methods
_decode_token(token, key = nil, verify: false, options: {})
click to toggle source
# File lib/firebase/authentication.rb, line 52 def _decode_token(token, key = nil, verify: false, options: {}) Rails.logger.info "#{self.class.name}\##{__method__} called." begin decoded_token = JWT.decode(token, key, verify, options) rescue JWT::ExpiredSignature => e raise "Firebase ID token has expired. Get a fresh token from your client app and try again. #{e.message}" rescue JWT::InvalidAudError, JWT::DecodeError, JWT::VerificationError => e raise "Firebase JWT Error. #{e.message}" rescue StandardError => e raise "Firebase ID token has invalid signature. #{e.message}" end { payload: decoded_token[0], header: decoded_token[1] } end
_fetch_public_keys()
click to toggle source
# File lib/firebase/authentication.rb, line 70 def _fetch_public_keys Rails.logger.info "#{self.class.name}\##{__method__} called." uri = URI.parse(CLIENT_CERT_URL) https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true res = https.start do https.get(uri.request_uri) end data = JSON.parse(res.body) if data["error"] msg = "Error fetching public keys for Google certs: #{data["error"]}" msg += " (#{res["error_description"]})" if data["error_description"] raise msg end data end
_validate_jwt(json)
click to toggle source
# File lib/firebase/authentication.rb, line 91 def _validate_jwt(json) Rails.logger.info "#{self.class.name}\##{__method__} called." error = _validate_jwt_header(json[:header]) error || _validate_jwt_payload(json[:payload]) end
_validate_jwt_header(header)
click to toggle source
# File lib/firebase/authentication.rb, line 97 def _validate_jwt_header(header) Rails.logger.info "#{self.class.name}\##{__method__} called." return 'Firebase ID token has no "kid" claim.' unless header["kid"] return "Firebase ID token has incorrect algorithm. Expected \"#{ALGORITHM}\" but got \"#{header["alg"]}\"."\ unless header["alg"] == ALGORITHM end
_validate_jwt_payload(payload)
click to toggle source
# File lib/firebase/authentication.rb, line 105 def _validate_jwt_payload(payload) Rails.logger.info "#{self.class.name}\##{__method__} called." project_id = ENV.fetch("FIREBASE_PROJECT_ID") unless payload["aud"] == project_id return "Firebase ID token has incorrect \'aud\' (audience) claim. Expected \"#{project_id}\" but got \"#{payload["aud"]}\"." end issuer = ISSUER_BASE_URL + project_id unless payload["iss"] == issuer return "Firebase ID token has incorrect \'iss\' (issuer) claim. Expected \"#{issuer}\" but got \"#{payload["iss"]}\"." end return 'Firebase ID token has no "sub" (subject) claim.' unless payload["sub"].is_a?(String) return 'Firebase ID token has an empty string "sub" (subject) claim.' if payload["sub"].empty? return 'Firebase ID token has "sub" (subject) claim longer than 128 characters.' if payload["sub"].size > 128 end