-
-
Notifications
You must be signed in to change notification settings - Fork 27
Fix: exp
type & overriding default exp
value
#28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
I was so confused why my |
Hi @damnmicrowave, Thanks a lot for opening this PR and pointing out the issue regarding dynamic exp configuration in jwt.sign(). I completely agree with both you and @fallow64 that this has been a point of confusion, and resolving it would indeed be a significant quality-of-life improvement for usability. I've forked this library and have been working on some enhancements, including a fix for this particular issue, in my version. I wanted to share it in case it might be helpful. In my version ( Given that the main repository may not have been updated for a while, my fork could serve as an alternative for anyone looking for these features or facing the same issues. I'm also open to feedback and further suggestions on my version. If you're interested, you can find more details here: |
WalkthroughThe JWT payload interface JWTPayloadSpec in src/index.ts was updated to allow the exp claim to be a number or a string, changing its type from number to number | string. No other files or logic were modified. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🧪 Early access (Sonnet 4.5): enabledWe are currently testing the Sonnet 4.5 model, which is expected to improve code review quality. However, this model may lead to increased noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience. Note:
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4 RFC7519#section-4.1.4} | ||
*/ | ||
exp?: number | ||
exp?: number | string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Critical: Type/validator mismatch will cause runtime validation failures.
The TypeScript type now allows exp
to be number | string
, but the validator schema at line 221 only accepts t.Number()
. When users pass a string value for exp
and schema validation is enabled, the validator will reject it at runtime, causing validation errors.
Additionally, per RFC 7519 section 4.1.4, the exp
claim in the final JWT payload must be a NumericDate (numeric value representing seconds since epoch). While jose's setExpirationTime()
accepts time-span strings like '1h'
as input for convenience, it converts them to numeric timestamps before encoding them into the JWT.
Since JWTPayloadSpec
represents the structure of the JWT payload (as stated in its JSDoc comment at lines 39-46), it should match the RFC 7519 specification where exp
is always numeric. The JWTPayloadInput
interface (line 122) correctly allows string | number
for input flexibility.
Recommendation:
- Revert
JWTPayloadSpec.exp
back tonumber
only (RFC-compliant) - Keep
JWTPayloadInput.exp
asstring | number
(already correct at line 122) - The existing implementation at lines 350-352 is correct and doesn't need changes
This maintains the distinction between input types (flexible) and payload types (RFC-compliant).
- exp?: number | string
+ exp?: number
Run the following script to verify how jose handles string exp values and confirm the validator mismatch:
Additionally, please search for the RFC 7519 specification on the exp
claim type:
🏁 Script executed:
#!/bin/bash
# Verify the validator schema for exp claim
echo "=== Validator schema for exp (should be t.Number()) ==="
rg -n "exp.*t\.(Optional|Number)" src/index.ts
echo ""
echo "=== All references to JWTPayloadSpec ==="
rg -n "JWTPayloadSpec" --type ts
echo ""
echo "=== Check if setExpirationTime is called with exp ==="
rg -n -A2 "setExpirationTime" src/index.ts
Length of output: 665
🌐 Web query:
RFC 7519 JWT exp claim type specification NumericDate
💡 Result:
Short answer — what NumericDate is and how exp uses it:
- NumericDate = number of seconds (not milliseconds) since 1970-01-01T00:00:00Z UTC, ignoring leap seconds; it may be an integer or a non‑integer (fractional seconds). [1]
- The "exp" claim’s value MUST be a number containing a NumericDate. The JWT MUST NOT be accepted if the current time is at or after that NumericDate; implementations MAY allow a small clock‑skew leeway (usually a few minutes). [1][2]
Sources:
[1] RFC 7519 (NumericDate definition and "exp" processing).
[2] Practical clarification (e.g., community/implementation notes confirming seconds, not milliseconds).
Revert JWTPayloadSpec.exp
to number
only (align with validator & RFC-compliant)
The interface in src/index.ts:89 was widened to number | string
, but the runtime schema (line 221: t.Optional(t.Number())
) only accepts numbers and RFC 7519 mandates exp
be a NumericDate number. Keep JWTPayloadInput.exp
as string|number
for input flexibility and revert the payload spec:
- exp?: number | string
+ exp?: number
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
exp?: number | string | |
++ b/src/index.ts | |
@@ -86,7 +86,7 @@ | |
// ... other fields in JWTPayloadSpec ... | |
exp?: number | |
// ... remaining fields ... |
🤖 Prompt for AI Agents
In src/index.ts around line 89, revert JWTPayloadSpec.exp to type number only
(remove the union with string) so the interface matches the runtime schema at
~line 221 (t.Optional(t.Number())) and RFC 7519; keep JWTPayloadInput.exp as
string|number for input parsing elsewhere if present. Update the type
declaration at line 89 from `exp?: number | string` to `exp?: number`, and
ensure any downstream usages or validators expect a NumericDate (number) rather
than a string.
Technically, jose supports passing timey strings, e.g.
'1h'
,'10days'
etc. (here)This PR updates the type of
exp
to bestring
as well as anumber
for that.Example:
Summary by CodeRabbit