note description: "Summary description for {JWT_UTILITIES}." author: "" date: "$Date$" revision: "$Revision$" class JWT_UTILITIES feature -- Constants alg_hs256: STRING = "HS256" -- HMAC SHA256. alg_none: STRING = "none" -- for unsecured token. feature -- Encoding base64url_encode (s: READABLE_STRING_8): STRING_8 local urlencoder: URL_ENCODER base64: BASE64 do create urlencoder create base64 Result := urlsafe_encode (base64.encoded_string (s)) end urlsafe_encode (s: READABLE_STRING_8): STRING_8 do create Result.make_from_string (s) Result.replace_substring_all ("=", "") Result.replace_substring_all ("+", "-") Result.replace_substring_all ("/", "_") end signature (a_enc_header, a_enc_payload: READABLE_STRING_8; a_secret: READABLE_STRING_8; alg: READABLE_STRING_8): STRING_8 local s: STRING do if alg.is_case_insensitive_equal (alg_none) then create Result.make_empty else create s.make (a_enc_header.count + 1 + a_enc_payload.count) s.append (a_enc_header) s.append_character ('.') s.append (a_enc_payload) if alg.is_case_insensitive_equal (alg_hs256) then Result := base64_hmacsha256 (s, a_secret) else Result := base64_hmacsha256 (s, a_secret) end Result := urlsafe_encode (Result) end end base64_hmacsha256 (s: READABLE_STRING_8; a_secret: READABLE_STRING_8): STRING_8 local hs256: HMAC_SHA256 do create hs256.make_ascii_key (a_secret) hs256.update_from_string (s) -- if Version >= EiffelStudio 17.11 then -- Result := hs256.base64_digest --lowercase_hexadecimal_string_digest -- else Result := base64_bytes_encoded_string (hs256.digest) -- end end feature {NONE} -- Implementation base64_bytes_encoded_string (a_bytes: SPECIAL [NATURAL_8]): STRING_8 -- Base64 string from `a_bytes`. --| Note: to be removed when 17.11 is not latest release anymore. local s: STRING i,n: INTEGER do from i := 1 n := a_bytes.count create s.make (n) until i > n loop s.append_code (a_bytes[i - 1]) i := i + 1 end Result := (create {BASE64}).encoded_string (s) end feature -- Decoding base64url_decode (s: READABLE_STRING_8): STRING_8 local urlencoder: URL_ENCODER base64: BASE64 do create urlencoder create base64 Result := base64.decoded_string (urlsafe_decode (s)) end urlsafe_decode (s: READABLE_STRING_8): STRING_8 local i: INTEGER do create Result.make_from_string (s) Result.replace_substring_all ("-", "+") Result.replace_substring_all ("_", "/") from i := Result.count \\ 4 until i = 0 loop i := i - 1 Result.extend ('=') end end feature -- Signature supported_signature_algorithms: LIST [READABLE_STRING_8] -- Supported signature algorithm `alg`? do create {ARRAYED_LIST [READABLE_STRING_8]} Result.make (2) Result.extend (alg_hs256) Result.extend (alg_none) end is_supporting_signature_algorithm (alg: READABLE_STRING_8): BOOLEAN -- Is supporting signature algorithm `alg`? do Result := across supported_signature_algorithms as ic some alg.is_case_insensitive_equal (ic.item) end end end