Skip to content

Drop jsonwebtoken dependency#94

Merged
tnull merged 1 commit intolightningdevkit:mainfrom
tankyleo:2026-02-drop-jsonwebtoken
May 5, 2026
Merged

Drop jsonwebtoken dependency#94
tnull merged 1 commit intolightningdevkit:mainfrom
tankyleo:2026-02-drop-jsonwebtoken

Conversation

@tankyleo
Copy link
Copy Markdown
Contributor

@tankyleo tankyleo commented Feb 9, 2026

Fixes #92.

@ldk-reviews-bot
Copy link
Copy Markdown

ldk-reviews-bot commented Feb 9, 2026

👋 Thanks for assigning @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@tankyleo tankyleo requested a review from tnull February 9, 2026 06:56
@tankyleo
Copy link
Copy Markdown
Contributor Author

tankyleo commented Feb 9, 2026

Fixes #92

@tankyleo tankyleo self-assigned this Feb 9, 2026
@tankyleo tankyleo linked an issue Feb 9, 2026 that may be closed by this pull request
@tankyleo tankyleo force-pushed the 2026-02-drop-jsonwebtoken branch from 7ff7d0a to bdd21e1 Compare February 9, 2026 07:07
@tnull
Copy link
Copy Markdown
Contributor

tnull commented Feb 9, 2026

Fixes #92

Note you'll have to put that in the OP otherwise it doesn't link the issue.

Comment thread rust/auth-impls/Cargo.toml Outdated
base64 = { version = "0.22.1", optional = true, default-features = false, features = ["std"] }
bitcoin_hashes = { version = "0.19", optional = true, default-features = false }
hex-conservative = { version = "1.0", optional = true, default-features = false }
rsa = { version = "0.9.10", optional = true, default-features = false, features = ["sha2"] }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We already have openssl in our tree - I do wonder if we could use openssl::rsa (https://docs.rs/openssl/latest/openssl/rsa/index.html) rather than this additional dependency?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thank you yes great idea

@tankyleo tankyleo requested a review from tnull February 10, 2026 07:34
Copy link
Copy Markdown
Contributor

@tnull tnull left a comment

Choose a reason for hiding this comment

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

Thanks for the update, some minor comments, otherwise looks good.

However, I think vss-server in general gets into the realm where it could use some some fuzzing or proptest coverage to ensure that our implementations behave as expected, are safe, never panic, etc.

Comment thread rust/auth-impls/src/jwt.rs Outdated

const BEARER_PREFIX: &str = "Bearer ";

fn parse_public_key_pem(pem: &str) -> Result<PKey<Public>, String> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we just return () or, if you prefer, a proper enum error type here? Using a string introduces some unnecessary allocations, and they can't easily be handled. Same goes for new then ofc.

serde_json = { version = "1.0.149", optional = true, default-features = false, features = ["std"] }

[dev-dependencies]
jsonwebtoken = { version = "9.3.0", default-features = false, features = ["use_pem"] }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If we already keep it as a dev dependency, can we add some parity/backwards compat tests that ensure our new custom implementation behaves the same way as this did?

@tnull
Copy link
Copy Markdown
Contributor

tnull commented Feb 23, 2026

@tankyleo Gentle ping here.

@tankyleo tankyleo requested a review from tnull May 2, 2026 00:05
@tankyleo
Copy link
Copy Markdown
Contributor Author

tankyleo commented May 2, 2026

Let me know what you think tnull, that last commit expands the scope of this PR a little where I add optional validation of exp claims, thought we could get this done along the way

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 1st Reminder

Hey @tnull! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Copy link
Copy Markdown
Contributor

@tnull tnull left a comment

Choose a reason for hiding this comment

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

Generally LGTM, but added some comments that Codex had for me. Seems they might be worth addressing even if not major?

Let me know what you think tnull, that last commit expands the scope of this PR a little where I add optional validation of exp claims, thought we could get this done along the way

Sounds good, though, AFAIU Codex thinks the validation didn't use to be optional before?

return Err(VssError::AuthError(String::from("The token is expired")));
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Codex:

  • High - rust/auth-impls/src/jwt.rs:103-118: aud is ignored. The old validator rejected tokens with an audience when no expected audience was configured; this now accepts tokens minted for another audience/service if signed by the same issuer.

Comment thread rust/auth-impls/src/jwt.rs Outdated
.map_err(|_| VssError::AuthError(String::from("Claims json decode failed")))?;

// Check if the token is expired
if let Some(exp) = claims.exp {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Codex:

  • High - rust/auth-impls/src/jwt.rs:39-40, rust/auth-impls/src/jwt.rs:111-116: JWTs without exp are now accepted. main used jsonwebtoken::Validation::new(Algorithm::RS256), which requires exp by default, so this creates non-expiring bearer tokens unless that policy change is
    intentional.


const BEARER_PREFIX: &str = "Bearer ";

fn parse_public_key_pem(pem: &str) -> Result<PKey<Public>, ()> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Codex:

  • Medium - rust/auth-impls/src/jwt.rs:45-54, rust/auth-impls/src/jwt.rs:94-98: RS256 is not tied to an RSA key. PKey::public_key_from_der accepts generic public keys, and OpenSSL verifies using the configured key type, so non-RSA keys are not rejected at setup. █
  • Medium - rust/auth-impls/src/jwt.rs:45-54: PEM parsing regressed to exact -----BEGIN PUBLIC KEY----- SPKI input. jsonwebtoken::from_rsa_pem also accepted common PKCS#1 -----BEGIN RSA PUBLIC KEY----- inputs, so some existing configs may fail to start.

@tankyleo
Copy link
Copy Markdown
Contributor Author

tankyleo commented May 5, 2026

Thanks addressed review, also passed the code through codex :)

@tankyleo tankyleo requested a review from tnull May 5, 2026 01:38
@tankyleo
Copy link
Copy Markdown
Contributor Author

tankyleo commented May 5, 2026

AFAIU Codex thinks the validation didn't use to be optional before?

Yes Codex is right, I misunderstood things given our old Claims struct only had a single sub member.

Copy link
Copy Markdown
Contributor

@tnull tnull left a comment

Choose a reason for hiding this comment

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

Feel free to squash.

/// Refer: https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2
sub: String,
/// Expiration Time
exp: u64,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Codex:

  - rust/auth-impls/src/jwt.rs:40: exp is now deserialized as u64 in the application claims. The old production path decoded into Claims { sub } and let jsonwebtoken validate exp separately, which accepted JWT NumericDate values encoded as JSON floats. Tokens with valid fractional exp values
    will now fail with Claims json decode failed, so this is a compatibility regression.

Maybe that's fine?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes I gave it some thought, would prefer to only add this if there is user demand.

This removes `time` from the dependency tree because the crate shipped
a security fix behind an MSRV bump.

Fixes lightningdevkit#92.

We make a best effort attempt to keep the same behavior as when we
validated JWTs using `jsonwebtoken`. This includes rejecting any JWTs
that have the `aud` field set. We also keep `jsonwebtoken` as a
dev-dependency and add parity tests.

Unlike `jsonwebtoken`, we now fail to decode JWTs that
contain `exp` fields with fractional parts.
@tankyleo tankyleo force-pushed the 2026-02-drop-jsonwebtoken branch from 4422d39 to 9ec254d Compare May 5, 2026 16:05
@tankyleo
Copy link
Copy Markdown
Contributor Author

tankyleo commented May 5, 2026

Squashed with no further changes

@tankyleo tankyleo requested a review from tnull May 5, 2026 16:12
@tnull tnull merged commit f446355 into lightningdevkit:main May 5, 2026
6 checks passed
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.

Revert time pin and/or drop jsonwebtoken dependency ASAP

3 participants