module JWT
Constants
- SIGNATURES
class OpenSSL::PKey::EC
alias_method :private?, :private_key?
end
Public Instance Methods
base64urldecode(val)
click to toggle source
# File lib/ruby_jwt.rb, line 141 def base64urldecode(val) begin case(val.length % 4) when 0 return Base64.urlsafe_decode64(val) when 2 return Base64.urlsafe_decode64("#{val}==") when 3 return Base64.urlsafe_decode64("#{val}=") else raise JWT::DecodeError.new("Illegal base64 string!") end rescue ArgumentError => e raise JWT::VerificationError.new(e.message) end end
base64urlencode(val)
click to toggle source
# File lib/ruby_jwt.rb, line 137 def base64urlencode(val) return Base64.urlsafe_encode64(val).gsub("=","") end
decode(token)
click to toggle source
# File lib/ruby_jwt.rb, line 51 def decode(token) jwt_parts = token.split(".") header = json_decode_data(jwt_parts[0]) payload = json_decode_data(jwt_parts[1]) return DecodeResponse.new(header,payload,jwt_parts[2],jwt_parts[0..1].join(".")) end
encode_data(data)
click to toggle source
# File lib/ruby_jwt.rb, line 101 def encode_data(data) return base64urlencode(JSON.generate(data)) end
encode_signature(data,key,alg)
click to toggle source
# File lib/ruby_jwt.rb, line 105 def encode_signature(data,key,alg) case alg when "none" return "" when "HS256","HS384", "HS512" return base64urlencode(OpenSSL::HMAC.digest(SIGNATURES[alg.gsub("HS","")], key, data)) when "RS256", "RS384", "RS512" return base64urlencode(key.sign(SIGNATURES[alg.gsub("RS","")],data)) when "ES256", "ES384", "ES512" return base64urlencode(key.dsa_sign_asn1(SIGNATURES[alg.gsub("ES","")].digest(data))) #return base64urlencode(key.sign(SIGNATURES[alg.gsub("ES","")],data)) else raise JWT::SignError.new("Unsupported signing method!") end end
json_decode_data(data)
click to toggle source
utility methods
# File lib/ruby_jwt.rb, line 97 def json_decode_data(data) return JSON.parse(base64urldecode(data),{:symbolize_names => true}) end
sign(payload,key,payload_options,header_options)
click to toggle source
# File lib/ruby_jwt.rb, line 27 def sign(payload,key,payload_options,header_options) jwt_parts = [] header_options = header_options || {} payload_options = payload_options || {} header_options[:alg] = header_options[:alg] || "HS256" if(header_options[:alg] != "none" and (!key)) raise JWT::SignError.new("Key cannot be blank if algorithm is not 'none'") end payload[:iat] = Time.now.to_i if(payload_options[:exp]) payload_options[:exp] += payload[:iat] end if(payload_options[:nbf]) payload_options[:nbf] += payload[:iat] end payload.merge!(payload_options) header_options[:typ] = header_options[:typ] || "JWT" jwt_parts << encode_data(header_options) jwt_parts << encode_data(payload) jwt_parts << encode_signature(jwt_parts.join("."),key, header_options[:alg]) return jwt_parts.join(".") end
time_compare(a,b)
click to toggle source
# File lib/ruby_jwt.rb, line 159 def time_compare(a,b) return false if a.nil? || b.nil? || a.empty? || b.empty? || a.bytesize != b.bytesize l = a.bytes compare = 0 b.bytes.each {|byte| compare += byte ^ l.shift} return compare == 0 end
verify(token,secret,options={})
click to toggle source
# File lib/ruby_jwt.rb, line 58 def verify(token,secret,options={}) raise VerificationError.new("JWT cannot be blank") if !token or token.empty? jwt_parts = token.split(".") raise VerificationError.new("JWT has invalid number of segments.") if(jwt_parts.count != 3 and secret) raise VerificationError.new("JWT has invalid number of segments.") if((jwt_parts.count < 2 or jwt_parts.count > 3) and !secret) #raise VerificationError.new("JWT signature is required.") if(jwt_parts[2].nil? and secret) jwt = decode(token) alg = jwt.header[:alg] payload = jwt.payload signature = jwt.signature.nil? ? "none" : base64urldecode(jwt.signature) current_time = Time.now.to_i if(payload[:exp] and current_time >= payload[:exp]) raise VerificationError.new("JWT is expired.") end if(payload[:nbf] and current_time < payload[:nbf]) raise VerificationError.new( "JWT nbf has not passed yet.") end if(options[:iss]) raise VerificationError.new("JWT issuer is invalid.") if options[:iss] != payload[:iss] end if(options[:aud]) audience = (options[:aud].is_a? Array) ? options[:aud] : [options[:aud]] raise VerificationError.new("JWT audience is invalid.") if !audience.include? payload[:aud] end raise VerificationError.new("JWT signature is invalid.") if !verify_signature(alg,secret,jwt.sign_input,signature) return jwt end
verify_signature(alg,key,data,signature)
click to toggle source
# File lib/ruby_jwt.rb, line 121 def verify_signature(alg,key,data,signature) case alg when "none" return true when "HS256","HS384", "HS512" return time_compare(signature,OpenSSL::HMAC.digest(SIGNATURES[alg.gsub("HS","")], key, data)) when "RS256", "RS384", "RS512" return key.verify(SIGNATURES[alg.gsub("RS","")],signature, data) when "ES256", "ES384", "ES512" return key.dsa_verify_asn1(SIGNATURES[alg.gsub("ES","")].digest(data),signature) #return key.verify(SIGNATURES[alg.gsub("ES","")],signature, data) else raise JWT::VerificationError.new("Unsupported signing method!") end end