fix(codegen): #927 — jwt.verify returns parsed object, not JSON-stringified string - #936
Merged
Merged
Conversation
…gified string The `jsonwebtoken.verify` (and `decode`) entries in NATIVE_MODULE_TABLE used `NR_STR`, which NaN-boxed the runtime's JSON-text `*mut StringHeader` return as a string. User code per the jsonwebtoken README expects an object — `decoded.sub` read `undefined`, auth middleware broke on every authenticated request after a successful signup. Add `NativeRetKind::ObjFromJsonStr` (alias `NR_OBJ_FROM_JSON_STR`) that automatically pipes the runtime's JSON-text result through a JSON-parse on the way out — symmetric counterpart of #915's `NA_JSON` on the argument side. Failure path (bad signature → null `*mut StringHeader`) routes through a new `js_json_parse_or_null` shim in `crates/perry-runtime/src/json.rs` so user code sees `null` instead of an uncaught "Unexpected end of JSON input" exception that aborts the process. Regression fixture exercises round-trip HS256 sign+verify and asserts `typeof decoded === "object"` plus `decoded.sub` indexability.
4 tasks
proggeramlug
added a commit
that referenced
this pull request
May 18, 2026
…s private PEM (#1025) The previous #927 fix (#936) made `jwt.verify` return the parsed claims object instead of the JSON text, but ES256 / RS256 tokens were still failing verification silently — the generic NativeModSig table routed every algorithm through `js_jwt_verify`, which was hardcoded to HS256. The token was signed correctly with ES256, then `Validation::new(Algorithm::HS256)` rejected it with `InvalidAlgorithm`, the runtime returned a null pointer, and `js_json_parse_or_null` surfaced it as `null` — breaking the shop-admin auth middleware on the very first authenticated request after a successful signup. Fix mirrors the `sign` side's algorithm-aware dispatch: - Add `js_jwt_verify_es256` / `js_jwt_verify_rs256` runtime functions in `perry-stdlib`. Both auto-derive the public key from a private PEM (PKCS#8 *or* SEC1 for EC, PKCS#8 *or* PKCS#1 for RSA) so callers can reuse the same PEM they passed to `sign` — matches Node `jsonwebtoken`'s ergonomics. Direct public-key PEMs (SPKI) also accepted unchanged. - Replace the generic NativeModSig `verify` row with `lower_jsonwebtoken_verify` in `lower_call/native.rs`. Routes on the canonical `algorithms: ['…']` array option as well as the singular `algorithm: '…'`. Falls back to HS256 when the option is absent or unparseable. Return path still pipes through `js_json_parse_or_null` so user code sees an object on success and `null` on failure (same contract as before). - Bonus: `js_jwt_sign_es256` now accepts SEC1 (`BEGIN EC PRIVATE KEY`) PEMs in addition to PKCS#8, which is what `openssl ecparam -genkey` emits by default. Symmetric with the new verify ergonomics. New `perry-stdlib` deps gated on `bundled-jsonwebtoken`: `p256` (EC public-key derivation), `rsa` (RSA public-key derivation), `spki` (PEM serialization). Verified with a 9-line standalone repro (sign + verify a token with `algorithms: ['ES256']`) — previously returned `null`, now returns the parsed claims object with `decoded.sub` accessible.
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.
Summary
jwt.verify(token, key, opts)(andjwt.decode(token)) now return a parsed object instead of the JSON-stringified text.decoded.subis indexable, auth middleware unblocks.NativeRetKind::ObjFromJsonStrto the native dispatch table — symmetric counterpart of Native server SIGSEGV atjwt.sign(...)(jsonwebtoken) after resumed async-step body — follow-up to #859 #915'sNA_JSONon the argument side. The arm pipes the runtime's*mut StringHeaderJSON-text return through a newjs_json_parse_or_nullshim so bad-signature failures still surface asnullinstead of throwingUnexpected end of JSON inputand aborting the process.test-files/test_issue_927_jwt_verify_returns_object.tsexercises HS256 round-trip sign+verify and assertstypeof decoded === "object",decoded.sub === "u-001",decoded.acc === "a-001".Test plan
cargo fmt --allcleancargo build --release -p perry-runtime -p perry-stdlib -p perrysucceeds./target/release/perry test-files/test_issue_927_jwt_verify_returns_object.ts -o /tmp/test_927 && /tmp/test_927printsdecoded typeof: object,decoded.sub: u-001,decoded.acc: a-001,issue 927 jwt.verify: okjwt.sign(...)(jsonwebtoken) after resumed async-step body — follow-up to #859 #915 regressiontest_issue_915_jwt_sign.tsstill passesnullwithout throwing/abortingjwt.decode(token)also returns object (mirror change)