class JWT::Decode

Decoding logic for JWT

Public Class Methods

new(jwt, key, verify, options, &keyfinder) click to toggle source
# File lib/jwt/decode.rb, line 11
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

Public Instance Methods

decode_segments() click to toggle source
# File lib/jwt/decode.rb, line 22
def decode_segments
  validate_segment_count!
  if @verify
    decode_crypto
    verify_signature
    verify_claims
  end
  raise(JWT::DecodeError, 'Not enough or too many segments') unless header && payload
  [payload, header]
end

Private Instance Methods

allowed_algorithms() click to toggle source
# File lib/jwt/decode.rb, line 50
def allowed_algorithms
  # Order is very important - first check for string keys, next for symbols
  algos = if @options.key?('algorithm')
    @options['algorithm']
  elsif @options.key?(:algorithm)
    @options[:algorithm]
  elsif @options.key?('algorithms')
    @options['algorithms']
  elsif @options.key?(:algorithms)
    @options[:algorithms]
  else
    []
  end
  Array(algos)
end
decode_crypto() click to toggle source
# File lib/jwt/decode.rb, line 89
def decode_crypto
  @signature = JWT::Base64.url_decode(@segments[2] || '')
end
find_key() { |header, payload| ... } click to toggle source
# File lib/jwt/decode.rb, line 66
def find_key(&keyfinder)
  key = (keyfinder.arity == 2 ? yield(header, payload) : yield(header))
  raise JWT::DecodeError, 'No verification key available' unless key
  key
end
header() click to toggle source
# File lib/jwt/decode.rb, line 93
def header
  @header ||= parse_and_decode @segments[0]
end
options_includes_algo_in_header?() click to toggle source
# File lib/jwt/decode.rb, line 46
def options_includes_algo_in_header?
  allowed_algorithms.any? { |alg| alg.casecmp(header['alg']).zero? }
end
parse_and_decode(segment) click to toggle source
# File lib/jwt/decode.rb, line 105
def parse_and_decode(segment)
  JWT::JSON.parse(JWT::Base64.url_decode(segment))
rescue ::JSON::ParserError
  raise JWT::DecodeError, 'Invalid segment encoding'
end
payload() click to toggle source
# File lib/jwt/decode.rb, line 97
def payload
  @payload ||= parse_and_decode @segments[1]
end
segment_length() click to toggle source
# File lib/jwt/decode.rb, line 85
def segment_length
  @segments.count
end
signing_input() click to toggle source
# File lib/jwt/decode.rb, line 101
def signing_input
  @segments.first(2).join('.')
end
validate_segment_count!() click to toggle source
# File lib/jwt/decode.rb, line 77
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 && header['alg'] == 'none'

  raise(JWT::DecodeError, 'Not enough or too many segments')
end
verify_claims() click to toggle source
# File lib/jwt/decode.rb, line 72
def verify_claims
  Verify.verify_claims(payload, @options)
  Verify.verify_required_claims(payload, @options)
end
verify_signature() click to toggle source
# File lib/jwt/decode.rb, line 35
def verify_signature
  raise(JWT::IncorrectAlgorithm, 'An algorithm must be specified') if allowed_algorithms.empty?
  raise(JWT::IncorrectAlgorithm, 'Token is missing alg header') unless header['alg']
  raise(JWT::IncorrectAlgorithm, 'Expected a different algorithm') unless options_includes_algo_in_header?

  @key = find_key(&@keyfinder) if @keyfinder
  @key = ::JWT::JWK::KeyFinder.new(jwks: @options[:jwks]).key_for(header['kid']) if @options[:jwks]

  Signature.verify(header['alg'], @key, signing_input, @signature)
end