Module: AnyCable::JWT::BasicImpl
- Defined in:
- lib/anycable/jwt.rb
Overview
Basic JWT encode/decode implementation suitable to our needs and not requiring external dependencies
Constant Summary collapse
- ALGORITHM =
"HS256"
Class Method Summary collapse
- .decode(token, secret_key) ⇒ Object
- .encode(payload, secret_key) ⇒ Object
- .sign(data, secret_key) ⇒ Object
Instance Method Summary collapse
Class Method Details
.decode(token, secret_key) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/anycable/jwt.rb', line 31 def decode(token, secret_key) header, payload, signature = token.split(".") # Check segments raise DecodeError, "Not enough or too many segments" unless header && payload && signature # Verify the algorithm decoded_header = ::JSON.parse(::Base64.urlsafe_decode64(header)) raise DecodeError, "Algorithm not supported" unless decoded_header["alg"] == ALGORITHM # Verify the signature expected_signature = sign("#{header}.#{payload}", secret_key) raise VerificationError, "Signature verification failed" unless secure_compare(signature, expected_signature) # Verify expiration decoded_payload = ::JSON.parse(::Base64.urlsafe_decode64(payload)) if decoded_payload.key?("exp") raise ExpiredSignature, "Signature has expired" if Time.now.to_i >= decoded_payload["exp"] end decoded_payload rescue JSON::ParserError, ArgumentError raise DecodeError, "Invalid segment encoding" end |
.encode(payload, secret_key) ⇒ Object
21 22 23 24 25 26 27 28 29 |
# File 'lib/anycable/jwt.rb', line 21 def encode(payload, secret_key) payload = ::Base64.urlsafe_encode64(payload.to_json, padding: false) headers = ::Base64.urlsafe_encode64({"alg" => ALGORITHM}.to_json, padding: false) header = "#{headers}.#{payload}" signature = sign(header, secret_key) "#{header}.#{signature}" end |
.sign(data, secret_key) ⇒ Object
72 73 74 75 76 77 |
# File 'lib/anycable/jwt.rb', line 72 def sign(data, secret_key) ::Base64.urlsafe_encode64( ::OpenSSL::HMAC.digest("SHA256", secret_key, data), padding: false ) end |
Instance Method Details
#secure_compare(a, b) ⇒ Object
59 60 61 62 63 |
# File 'lib/anycable/jwt.rb', line 59 def secure_compare(a, b) return false if a.bytesize != b.bytesize OpenSSL.fixed_length_secure_compare(a, b) end |