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)

Move algorithms matching the JWT alg header to the beginning of the list
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