class JWT::Decode
Experimental RBS support (using type sampling data from the type_fusion
project).
# sig/jwt/decode.rbs class JWT::Decode def payload: () -> untyped end
Decoding logic for JWT
def alg_in_header
def alg_in_header header['alg'] end
def allowed_algorithms
def allowed_algorithms @allowed_algorithms ||= resolve_allowed_algorithms end
def allowed_and_valid_algorithms
def allowed_and_valid_algorithms @allowed_and_valid_algorithms ||= allowed_algorithms.select { |alg| alg.valid_alg?(alg_in_header) } end
def decode_segments
def decode_segments validate_segment_count! if @verify decode_signature verify_algo set_key verify_signature verify_claims end raise(JWT::DecodeError, 'Not enough or too many segments') unless header && payload [payload, header] end
def decode_signature
def decode_signature @signature = ::JWT::Base64.url_decode(@segments[2] || '') end
def find_key(&keyfinder)
def find_key(&keyfinder) key = (keyfinder.arity == 2 ? yield(header, payload) : yield(header)) # key can be of type [string, nil, OpenSSL::PKey, Array] return key if key && !Array(key).empty? raise JWT::DecodeError, 'No verification key available' end
def given_algorithms
def given_algorithms ALGORITHM_KEYS.each do |alg_key| alg = @options[alg_key] return Array(alg) if alg end [] end
def header
def header @header ||= parse_and_decode @segments[0] end
def initialize(jwt, key, verify, options, &keyfinder)
def initialize(jwt, key, verify, options, &keyfinder) raise(JWT::DecodeError, 'Nil JSON web token') unless jwt @jwt = jwt @key = key @options = options @segments = jwt.split('.') @verify = verify @signature = '' @keyfinder = keyfinder end
def none_algorithm?
def none_algorithm? alg_in_header == 'none' end
def parse_and_decode(segment)
def parse_and_decode(segment) JWT::JSON.parse(::JWT::Base64.url_decode(segment)) rescue ::JSON::ParserError raise JWT::DecodeError, 'Invalid segment encoding' end
def payload
Experimental RBS support (using type sampling data from the type_fusion
project).
def payload: () -> untyped
This signature was generated using 1 sample from 1 application.
def payload @payload ||= parse_and_decode @segments[1] end
def resolve_allowed_algorithms
def resolve_allowed_algorithms algs = given_algorithms.map do |alg| if Algos.implementation?(alg) alg else Algos.create(alg) end end sort_by_alg_header(algs) end
def segment_length
def segment_length @segments.count end
def set_key
def set_key @key = find_key(&@keyfinder) if @keyfinder @key = ::JWT::JWK::KeyFinder.new(jwks: @options[:jwks], allow_nil_kid: @options[:allow_nil_kid]).key_for(header['kid']) if @options[:jwks] if (x5c_options = @options[:x5c]) @key = X5cKeyFinder.new(x5c_options[:root_certificates], x5c_options[:crls]).from(header['x5c']) end end
def signing_input
def signing_input @segments.first(2).join('.') end
def sort_by_alg_header(algs)
def sort_by_alg_header(algs) return algs if algs.size <= 1 algs.partition { |alg| alg.valid_alg?(alg_in_header) }.flatten end
def validate_segment_count!
def validate_segment_count! return if segment_length == 3 return if !@verify && segment_length == 2 # If no verifying required, the signature is not needed return if segment_length == 2 && none_algorithm? raise(JWT::DecodeError, 'Not enough or too many segments') end
def verify_algo
def verify_algo raise(JWT::IncorrectAlgorithm, 'An algorithm must be specified') if allowed_algorithms.empty? raise(JWT::IncorrectAlgorithm, 'Token is missing alg header') unless alg_in_header raise(JWT::IncorrectAlgorithm, 'Expected a different algorithm') if allowed_and_valid_algorithms.empty? end
def verify_claims
def verify_claims Verify.verify_claims(payload, @options) Verify.verify_required_claims(payload, @options) end
def verify_signature
def verify_signature return unless @key || @verify return if none_algorithm? raise JWT::DecodeError, 'No verification key available' unless @key return if Array(@key).any? { |key| verify_signature_for?(key) } raise(JWT::VerificationError, 'Signature verification failed') end
def verify_signature_for?(key)
def verify_signature_for?(key) allowed_and_valid_algorithms.any? do |alg| alg.verify(data: signing_input, signature: @signature, verification_key: key) end end