concord-consortium/rigse

View on GitHub
rails/lib/signed_jwt.rb

Summary

Maintainability
A
0 mins
Test Coverage
module SignedJWT

  require 'jwt'

  class Error < StandardError
  end

  def self.create_portal_token(user, claims={}, expires_in=3600)
    now = Time.now.to_i
    payload = {
      alg: self.hmac_algorithm,
      iat: now,
      exp: now + expires_in,
      uid: user.id
    }
    # merge claims into payload, preventing duplicates
    payload.merge!(claims) { |key, old, new| fail "Duplicate JWT claim key: #{key}" }
    begin
      JWT.encode payload, self.hmac_secret, self.hmac_algorithm
    rescue StandardError => e
      raise SignedJWT::Error.new(e.message)
    end
  end

  def self.decode_portal_token(token)
    begin
      decoded = JWT.decode token, self.hmac_secret, true, {algorithm: self.hmac_algorithm}
    rescue StandardError => e
      raise SignedJWT::Error.new(e.message)
    end
    {data: decoded[0], header: decoded[1]}
  end

  def self.create_firebase_token(uid, firebase_app_name, expires_in=3600, claims={})
    app = FirebaseApp.find_by_name(firebase_app_name)
    raise SignedJWT::Error.new("Unknown firebase app name: #{firebase_app_name}") if app.nil?

    now = Time.now.to_i
    payload = {
      alg: self.rsa_algorithm,
      iss: app.client_email,
      sub: app.client_email,
      aud: 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
      iat: now,
      exp: now + expires_in,
      uid: uid
    }

    begin
      # merge claims into payload, preventing duplicates
      payload.merge!(claims) { |key, old, new| fail "Duplicate JWT claim key: #{key}" }
      rsa_private = OpenSSL::PKey::RSA.new(app.private_key)
      JWT.encode payload, rsa_private, self.rsa_algorithm
    rescue StandardError => e
      raise SignedJWT::Error.new(e.message)
    end
  end

  # for tests to check token
  def self.decode_firebase_token(token, firebase_app_name)
    app = FirebaseApp.find_by_name(firebase_app_name)
    raise SignedJWT::Error.new("Unknown firebase app name: #{firebase_app_name}") if app.nil?

    begin
      rsa_private = OpenSSL::PKey::RSA.new(app.private_key)
      decoded = JWT.decode token, rsa_private, true, {algorithm: self.rsa_algorithm}
    rescue StandardError => e
      raise SignedJWT::Error.new(e.message)
    end
    {data: decoded[0], header: decoded[1]}
  end

  def self.is_valid_private_key?(private_key)
    begin
      rsa_private = OpenSSL::PKey::RSA.new(private_key)
      JWT.encode({}, rsa_private, self.rsa_algorithm)
    rescue StandardError => e
      return false
    end
    return true
  end

  private

  def self.hmac_algorithm
    'HS256'
  end

  def self.rsa_algorithm
    'RS256'
  end

  def self.hmac_secret
    secret = ENV['JWT_HMAC_SECRET']
    raise SignedJWT::Error.new('No HMAC signing secret (JWT_HMAC_SECRET) found in environment') if secret.blank?
    secret
  end
end