27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
# File 'lib/seekmodo/sdk/pairing.rb', line 27
def verify_and_extract(jwt_token)
, payload, _sig = JWT.decode(jwt_token, nil, false)
alg = ["alg"].to_s
raise SeekmodoError, "Unsupported pairing JWT alg \"#{alg}\"; expected EdDSA." unless alg == "EdDSA"
kid = ["kid"].to_s
raise SeekmodoError, "Pairing JWT is missing kid header." if kid.empty?
jwk = lookup_key(kid, refresh: false)
jwk = lookup_key(kid, refresh: true) if jwk.nil?
raise SeekmodoError, "No pairing JWKS key matches kid=\"#{kid}\"; rotation lag?" if jwk.nil?
public_key_raw = base64url_decode(jwk["x"].to_s)
raise SeekmodoError, "Pairing JWKS key has wrong byte length for Ed25519." unless public_key_raw.bytesize == 32
public_key = OpenSSL::PKey.read({
kty: "OKP",
crv: "Ed25519",
x: jwk["x"]
}.to_json)
JWT.decode(
jwt_token,
public_key,
true,
{ algorithm: "EdDSA" }
)
now = @clock.call
exp = payload["exp"].to_i
iat = payload["iat"].to_i
raise SeekmodoError, "Pairing JWT has expired." if exp > 0 && exp < now
raise SeekmodoError, "Pairing JWT is older than the 10-minute replay window." if iat > 0 && now - iat > MAX_TOKEN_AGE_SECONDS
payload
rescue JWT::DecodeError => e
raise SeekmodoError, "Pairing JWT signature verification failed.", e.backtrace
end
|