# frozen_string_literal: true require_relative 'algos' require_relative 'claims_validator' # JWT::Encode module module JWT # Encoding logic for JWT class Encode ALG_KEY = 'alg' def initialize(options) @payload = options[:payload] @key = options[:key] @algorithm = resolve_algorithm(options[:algorithm]) @headers = options[:headers].transform_keys(&:to_s) @headers[ALG_KEY] = @algorithm.alg end def segments validate_claims! combine(encoded_header_and_payload, encoded_signature) end private def resolve_algorithm(algorithm) return algorithm if Algos.implementation?(algorithm) Algos.create(algorithm) end def encoded_header @encoded_header ||= encode_header end def encoded_payload @encoded_payload ||= encode_payload end def encoded_signature @encoded_signature ||= encode_signature end def encoded_header_and_payload @encoded_header_and_payload ||= combine(encoded_header, encoded_payload) end def encode_header encode_data(@headers) end def encode_payload encode_data(@payload) end def signature @algorithm.sign(data: encoded_header_and_payload, signing_key: @key) end def validate_claims! return unless @payload.is_a?(Hash) ClaimsValidator.new(@payload).validate! end def encode_signature ::JWT::Base64.url_encode(signature) end def encode_data(data) ::JWT::Base64.url_encode(JWT::JSON.generate(data)) end def combine(*parts) parts.join('.') end end end