class AppleIdToken::Validator

Constants

APPLE_ISSUER
APPLE_JWKS_URI
HTTP_OK
JWT_RS256

Public Class Methods

validate(token:, aud:) click to toggle source
# File lib/apple_id_token.rb, line 23
def validate(token:, aud:)
  public_keys = get_public_keys
  if public_keys
    payload = check_against_certs(token, aud, public_keys)

    unless payload
      raise JWTSignatureError, 'Token not verified as issued by Apple'
    end
  else
    raise PublicKeysError, 'Unable to retrieve Apple public keys'
  end

  payload
end

Private Class Methods

check_against_certs(token, aud, public_keys) click to toggle source
# File lib/apple_id_token.rb, line 48
def check_against_certs(token, aud, public_keys)
  payload = nil
  public_keys.each do |public_key|
    # As jwk from jwt library needs Hashes with keys as symbols.
    public_key = Hash[public_key.map{ |k, v| [k.to_sym, v] }]

    begin
      jwk = JWT::JWK.import(public_key)
      decoded_token = JWT.decode(token, jwk.public_key , !!public_key, {
          algorithm: JWT_RS256,
          iss: APPLE_ISSUER, verify_iss: true,
          aud: aud, verify_aud: true
        }
      )

      return payload = decoded_token.first
    rescue JWT::JWKError
      raise InvalidPublicKeyError, 'Provided public key was invalid'
    rescue JWT::ExpiredSignature
      raise JWTExpiredSignatureError, 'Token signature is expired'
    rescue JWT::InvalidIssuerError
      raise JWTSignatureError, 'Token not verified as issued by Apple'
    rescue JWT::InvalidAudError
      raise JWTAudienceError, 'Token audience mismatch'
    rescue JWT::DecodeError => e
      nil # Try another public key.
    end
  end

  payload
end
get_public_keys() click to toggle source
# File lib/apple_id_token.rb, line 40
def get_public_keys
  response = HTTParty.get(APPLE_JWKS_URI)
  return false unless response.code == HTTP_OK

  json_body = JSON.parse(response.body)
  json_body['keys']
end