Skip to content

Commit d71b8dd

Browse files
committed
More comments addressed
1 parent c9cb9a5 commit d71b8dd

2 files changed

Lines changed: 38 additions & 10 deletions

File tree

lib/jwt/encoded_nested_token.rb

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,17 @@ module JWT
66
# Unwraps all nesting levels and provides an Enumerable interface over the token layers
77
# (outermost to innermost).
88
#
9-
# @example Verifying a Nested JWT
9+
# @example Verifying a Nested JWT with a shared algorithm
1010
# nested = JWT::EncodedNestedToken.new(nested_jwt_string)
11-
# nested.verify!(algorithm: ['RS256', 'HS256'], key: [rsa_public, 'inner_secret'])
11+
# nested.verify!(algorithm: 'HS256', key: [outer_secret, inner_secret])
12+
# nested.last.payload # => { 'user_id' => 123 }
13+
#
14+
# @example Verifying with mixed algorithms using key_finder
15+
# nested = JWT::EncodedNestedToken.new(nested_jwt_string)
16+
# nested.verify!(
17+
# algorithm: %w[RS256 HS256],
18+
# key_finder: ->(token) { key_map[token.header['alg']] }
19+
# )
1220
# nested.last.payload # => { 'user_id' => 123 }
1321
#
1422
# @example Inspecting layers
@@ -27,16 +35,22 @@ class EncodedNestedToken
2735
def initialize(jwt, max_depth: MAX_DEPTH)
2836
raise ArgumentError, 'Provided JWT must be a String' unless jwt.is_a?(String)
2937

38+
@jwt = jwt
3039
@max_depth = max_depth
31-
@tokens = unwrap(jwt)
40+
@verified = false
3241
end
3342

3443
def each(&block)
35-
@tokens.each(&block)
44+
tokens.each(&block)
3645
end
3746

47+
# Returns the innermost token. Requires {#verify!} to have been called first.
48+
# @return [JWT::EncodedToken] the innermost token.
49+
# @raise [JWT::DecodeError] if the token has not been verified.
3850
def last
39-
@tokens.last
51+
raise JWT::DecodeError, 'Verify the token before accessing the innermost token' unless @verified
52+
53+
tokens.last
4054
end
4155

4256
# Verifies signatures at each nesting level and claims on the innermost token.
@@ -58,12 +72,17 @@ def verify!(algorithm:, key: nil, key_finder: nil, claims: nil)
5872
token.verify_signature!(algorithm: algorithm, key: key, key_finder: key_finder)
5973
end
6074

75+
@verified = true
6176
claims.is_a?(Array) ? last.verify_claims!(*claims) : last.verify_claims!(claims)
6277
self
6378
end
6479

6580
private
6681

82+
def tokens
83+
@tokens ||= unwrap(@jwt)
84+
end
85+
6786
def unwrap(jwt)
6887
tokens = []
6988
current = jwt

spec/jwt/encoded_nested_token_spec.rb

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,19 @@ def create_nested(inner, algorithm:, key:)
5151
end
5252

5353
describe '#last' do
54-
it 'returns the innermost token' do
54+
it 'raises DecodeError before verification' do
5555
nested_jwt = create_nested(inner_jwt, algorithm: 'HS256', key: outer_secret)
5656
nested = described_class.new(nested_jwt)
5757

58-
expect(nested.last.unverified_payload).to eq(inner_payload)
58+
expect { nested.last }.to raise_error(JWT::DecodeError, /Verify the token before/)
59+
end
60+
61+
it 'returns the innermost token after verification' do
62+
nested_jwt = create_nested(inner_jwt, algorithm: 'HS256', key: outer_secret)
63+
nested = described_class.new(nested_jwt)
64+
nested.verify!(algorithm: 'HS256', key: [outer_secret, inner_secret])
65+
66+
expect(nested.last.payload).to eq(inner_payload)
5967
end
6068
end
6169

@@ -161,8 +169,9 @@ def create_nested(inner, algorithm:, key:)
161169
current = create_nested(current, algorithm: 'HS256', key: "key_#{i}")
162170
end
163171

172+
nested = described_class.new(current)
164173
expect do
165-
described_class.new(current)
174+
nested.count
166175
end.to raise_error(JWT::DecodeError, /exceeds maximum depth/)
167176
end
168177

@@ -171,11 +180,11 @@ def create_nested(inner, algorithm:, key:)
171180
level3 = create_nested(level2, algorithm: 'HS256', key: 'key3')
172181

173182
expect do
174-
described_class.new(level3, max_depth: 2)
183+
described_class.new(level3, max_depth: 2).count
175184
end.to raise_error(JWT::DecodeError, 'Nested JWT exceeds maximum depth of 2')
176185

177186
expect do
178-
described_class.new(level3, max_depth: 5)
187+
described_class.new(level3, max_depth: 5).count
179188
end.not_to raise_error
180189
end
181190
end

0 commit comments

Comments
 (0)