fix(api): require exp claim when verifying access tokens - #779
Merged
Conversation
SashaMIT
requested review from
cloudwebrtc,
lukasIO and
xianshijing-lk
as code owners
August 19, 2026 04:57
A shared options dict from a ternary widens to dict[str, object] and fails livekit-api type-check against PyJWT Options.
This was referenced Aug 19, 2026
lukasIO
approved these changes
Aug 19, 2026
lukasIO
left a comment
Contributor
There was a problem hiding this comment.
thanks for catching this!
lukasIO
reviewed
Aug 19, 2026
Comment on lines
+238
to
+239
| # Inline each options literal so mypy matches PyJWT's Options TypedDict | ||
| # (a shared dict from a ternary widens to dict[str, object]). |
Contributor
There was a problem hiding this comment.
Suggested change
| # Inline each options literal so mypy matches PyJWT's Options TypedDict | |
| # (a shared dict from a ternary widens to dict[str, object]). |
we can remove this section of the comment
Contributor
Author
There was a problem hiding this comment.
Removed. Thanks for the review.
Contributor
Author
|
Dropped the mypy note. Thanks for the review. |
Contributor
Author
|
Thanks for the review and the merge. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
TokenVerifier.verifydecodes with issuer, HS256, and leeway, but does not requireexp. PyJWT treats a missingexpas optional, so a hand-rolled token with a valid signature and no expiry verifies forever.First-party
AccessToken.to_jwtalways setsexp. This matches the gap livekit/protocol#1706 closed on the Go verifier (jwt.WithExpirationRequired).Fix
When
verify_signatureis true (the production path), passrequire: ["exp"].verify_signature=False(simulate/dev) is unchanged.Threat-model: the attacker can mint or obtain an HS256 token that omits
exp. They do not control the verifier secret or clock. Without the claim, signature verification still succeeds and the credential never ages out. That is permanent access from a forgotten expiry, not host or agent authority.Test plan
pytest tests/api/test_access_token.py(5/5)require: ["exp"]makestest_verify_token_missing_expfail (missing-exp token is accepted)Made with Cursor