Skip to content

Nested token Friday night PoC#721

Draft
anakinj wants to merge 3 commits intojwt:mainfrom
anakinj:nested-jwt-poc
Draft

Nested token Friday night PoC#721
anakinj wants to merge 3 commits intojwt:mainfrom
anakinj:nested-jwt-poc

Conversation

@anakinj
Copy link
Member

@anakinj anakinj commented Mar 20, 2026

Description

This is just me vibing and brainstorming

Checklist

Before the PR can be merged be sure the following are checked:

  • There are tests for the fix or feature added/changed
  • A description of the changes and a reference to the PR has been added to CHANGELOG.md. More details in the CONTRIBUTING.md

# @raise [JWT::DecodeError] if key count doesn't match nesting depth.
# @raise [JWT::VerificationError] if any signature verification fails.
def verify!(keys:, claims: nil)
raise JWT::DecodeError, "Expected #{count} key configurations, got #{keys.length}" unless keys.length == count
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really care, the same key could be used to validate multiple tokens

token.verify_signature!(algorithm: keys[index][:algorithm], key: keys[index][:key])
end

last.verify_claims!(*Array(claims).compact)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we only verify the last tokens claims?

current = jwt

loop do
raise JWT::DecodeError, "Nested JWT exceeds maximum depth of #{MAX_DEPTH}" if tokens.length >= MAX_DEPTH
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Max depth could be an instance variable, so it can be changed if needed

# The payload is base64url-encoded directly (not JSON-encoded).
#
# @example Creating a Nested JWT
# inner_jwt = JWT.encode({ user_id: 123 }, 'inner_secret', 'HS256')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets use the class based generations for consistency

end

def last
@tokens.last
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can access last before the chain has been verified. Maybe we need to protect against that?

raise ArgumentError, 'Provided JWT must be a String' unless jwt.is_a?(String)

@max_depth = max_depth
@tokens = unwrap(jwt)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make it unwrap lazy when tokens are acessed?

#
# @example Verifying a Nested JWT
# nested = JWT::EncodedNestedToken.new(nested_jwt_string)
# nested.verify!(algorithm: ['RS256', 'HS256'], key: [rsa_public, 'inner_secret'])
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think the example in the comment is wrong. mixing algos did not work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant