lib/jwt.rb in jwt-0.1.4 vs lib/jwt.rb in jwt-0.1.5
- old
+ new
@@ -1,18 +1,18 @@
-#
+#
# JSON Web Token implementation
-#
+#
# Should be up to date with the latest spec:
# http://self-issued.info/docs/draft-jones-json-web-token-06.html
require "base64"
require "openssl"
-require "json"
+require "multi_json"
module JWT
class DecodeError < Exception; end
-
+
def self.sign(algorithm, msg, key)
if ["HS256", "HS384", "HS512"].include?(algorithm)
sign_hmac(algorithm, msg, key)
elsif ["RS256", "RS384", "RS512"].include?(algorithm)
sign_rsa(algorithm, msg, key)
@@ -30,56 +30,64 @@
end
def self.sign_hmac(algorithm, msg, key)
OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new(algorithm.sub('HS', 'sha')), key, msg)
end
-
+
def self.base64url_decode(str)
str += '=' * (4 - str.length.modulo(4))
Base64.decode64(str.gsub("-", "+").gsub("_", "/"))
end
-
+
def self.base64url_encode(str)
Base64.encode64(str).gsub("+", "-").gsub("/", "_").gsub("\n", "").gsub('=', '')
- end
-
- def self.encode(payload, key, algorithm='HS256')
+ end
+
+ def self.encode(payload, key, algorithm='HS256', header_fields={})
algorithm ||= "none"
segments = []
- header = {"typ" => "JWT", "alg" => algorithm}
- segments << base64url_encode(header.to_json)
- segments << base64url_encode(payload.to_json)
+ header = {"typ" => "JWT", "alg" => algorithm}.merge(header_fields)
+ segments << base64url_encode(MultiJson.encode(header))
+ segments << base64url_encode(MultiJson.encode(payload))
signing_input = segments.join('.')
if algorithm != "none"
signature = sign(algorithm, signing_input, key)
segments << base64url_encode(signature)
else
segments << ""
end
segments.join('.')
end
-
- def self.decode(jwt, key=nil, verify=true)
+
+ def self.decode(jwt, key=nil, verify=true, &keyfinder)
segments = jwt.split('.')
raise JWT::DecodeError.new("Not enough or too many segments") unless [2,3].include? segments.length
header_segment, payload_segment, crypto_segment = segments
signing_input = [header_segment, payload_segment].join('.')
begin
- header = JSON.parse(base64url_decode(header_segment))
- payload = JSON.parse(base64url_decode(payload_segment))
+ header = MultiJson.decode(base64url_decode(header_segment))
+ payload = MultiJson.decode(base64url_decode(payload_segment))
signature = base64url_decode(crypto_segment) if verify
rescue JSON::ParserError
raise JWT::DecodeError.new("Invalid segment encoding")
end
if verify == true
algo = header['alg']
- if ["HS256", "HS384", "HS512"].include?(algo)
- raise JWT::DecodeError.new("Signature verification failed") unless signature == sign_hmac(algo, signing_input, key)
- elsif ["RS256", "RS384", "RS512"].include?(algo)
- raise JWT::DecodeError.new("Signature verification failed") unless verify_rsa(algo, key, signing_input, signature)
- else
- raise JWT::DecodeError.new("Algorithm not supported")
+ if keyfinder
+ key = keyfinder.call(header)
+ end
+
+ begin
+ if ["HS256", "HS384", "HS512"].include?(algo)
+ raise JWT::DecodeError.new("Signature verification failed") unless signature == sign_hmac(algo, signing_input, key)
+ elsif ["RS256", "RS384", "RS512"].include?(algo)
+ raise JWT::DecodeError.new("Signature verification failed") unless verify_rsa(algo, key, signing_input, signature)
+ else
+ raise JWT::DecodeError.new("Algorithm not supported")
+ end
+ rescue OpenSSL::PKey::PKeyError
+ raise JWT::DecodeError.new("Signature verification failed")
end
end
payload
end