63 lines
2 KiB
Ruby
63 lines
2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'base64'
|
|
require 'jwt/decode'
|
|
require 'jwt/default_options'
|
|
require 'jwt/encode'
|
|
require 'jwt/error'
|
|
require 'jwt/signature'
|
|
require 'jwt/verify'
|
|
|
|
# JSON Web Token implementation
|
|
#
|
|
# Should be up to date with the latest spec:
|
|
# https://tools.ietf.org/html/rfc7519
|
|
module JWT
|
|
include JWT::DefaultOptions
|
|
|
|
module_function
|
|
|
|
def encode(payload, key, algorithm = 'HS256', header_fields = {})
|
|
encoder = Encode.new payload, key, algorithm, header_fields
|
|
encoder.segments
|
|
end
|
|
|
|
def decode(jwt, key = nil, verify = true, custom_options = {}, &keyfinder)
|
|
raise(JWT::DecodeError, 'Nil JSON web token') unless jwt
|
|
|
|
merged_options = DEFAULT_OPTIONS.merge(custom_options)
|
|
|
|
decoder = Decode.new jwt, verify
|
|
header, payload, signature, signing_input = decoder.decode_segments
|
|
decode_verify_signature(key, header, payload, signature, signing_input, merged_options, &keyfinder) if verify
|
|
|
|
Verify.verify_claims(payload, merged_options) if verify
|
|
|
|
raise(JWT::DecodeError, 'Not enough or too many segments') unless header && payload
|
|
|
|
[payload, header]
|
|
end
|
|
|
|
def decode_verify_signature(key, header, payload, signature, signing_input, options, &keyfinder)
|
|
algo, key = signature_algorithm_and_key(header, payload, key, &keyfinder)
|
|
|
|
raise(JWT::IncorrectAlgorithm, 'An algorithm must be specified') if allowed_algorithms(options).empty?
|
|
raise(JWT::IncorrectAlgorithm, 'Expected a different algorithm') unless allowed_algorithms(options).include?(algo)
|
|
|
|
Signature.verify(algo, key, signing_input, signature)
|
|
end
|
|
|
|
def signature_algorithm_and_key(header, payload, key, &keyfinder)
|
|
key = (keyfinder.arity == 2 ? yield(header, payload) : yield(header)) if keyfinder
|
|
raise JWT::DecodeError, 'No verification key available' unless key
|
|
[header['alg'], key]
|
|
end
|
|
|
|
def allowed_algorithms(options)
|
|
if options.key?(:algorithm)
|
|
[options[:algorithm]]
|
|
else
|
|
options[:algorithms] || []
|
|
end
|
|
end
|
|
end
|