Skip to content

Commit

Permalink
Merge pull request #7 from carbonteq/add-optional-caching
Browse files Browse the repository at this point in the history
Add JwtCacheClient
  • Loading branch information
volf52 committed Jun 27, 2023
2 parents 67e0079 + 6d2ab5a commit 3d66fe2
Show file tree
Hide file tree
Showing 11 changed files with 294 additions and 118 deletions.
5 changes: 5 additions & 0 deletions .changeset/tiny-comics-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@carbonteq/jwt": minor
---

Add cache opt
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ crate-type = ["cdylib"]

[dependencies]
jsonwebtoken = { version = "8.3.0" }
mini-moka = { version = "0.10.0", default_features = false }
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { version = "2.12.2", default-features = false, features = [
"napi4",
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ SUITE <Sign token>: Fastest is @carbonteq/jwt
### Verifying Token ([bench/verify.mjs](./bench/verify.mjs))

```
jsonwebtoken x 2,068 ops/sec ±0.46% (187 runs sampled)
jose x 55,797 ops/sec ±0.29% (182 runs sampled)
fast-jwt x 68,474 ops/sec ±0.79% (182 runs sampled)
@carbonteq/jwt x 166,543 ops/sec ±0.73% (189 runs sampled)
SUITE <Verify Token>: Fastest is @carbonteq/jwt
jsonwebtoken x 2,110 ops/sec ±0.95% (186 runs sampled)
jose x 54,067 ops/sec ±0.35% (182 runs sampled)
fast-jwt x 108,051 ops/sec ±0.65% (187 runs sampled)
fast-jwt#withCache x 221,852 ops/sec ±1.00% (185 runs sampled)
@carbonteq/jwt x 233,830 ops/sec ±3.21% (181 runs sampled)
@carbonteq/jwt#withCache x 440,433 ops/sec ±9.85% (172 runs sampled)
SUITE <Verify Token>: Fastest is @carbonteq/jwt#withCache
```
26 changes: 23 additions & 3 deletions bench/verify.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { JwtClient } from '../index.js';
import { JwtClient, JwtCacheClient } from '../index.js';
import bench from 'benchmark';
import chalk from 'chalk';
import fastJwt from 'fast-jwt';
Expand All @@ -13,8 +13,9 @@ const minSamples = 100;
const encodedKey = new TextEncoder().encode(secret);
const payload = { userId: 'abc123' };

const client = new JwtClient(secret);
const expires_in = 60000;
const client = new JwtClient(secret);
const cacheClient = new JwtCacheClient(secret, expires_in, 2);

const joseSign = async (payload) => {
const s = new jose.SignJWT(payload);
Expand All @@ -27,6 +28,12 @@ const joseSigned = await joseSign(payload);
const jwtSigned = jwt.sign(payload, secret);

const signer = fastJwt.createSigner({ key: secret });
const fastJwtVerify = fastJwt.createVerifier({ key: secret, cache: false });
const fastJwtCacheVerify = fastJwt.createVerifier({
key: secret,
cache: true,
cacheTTL: expires_in,
});
const fastJwtSigned = signer(payload);

const ctJwtSigned = client.sign(payload, expires_in);
Expand All @@ -50,18 +57,31 @@ suite
.add(
'fast-jwt',
() => {
const fastJwtVerify = fastJwt.createVerifier({ key: secret });
fastJwtVerify(fastJwtSigned);
},
{ minSamples },
)
.add(
'fast-jwt#withCache',
() => {
fastJwtCacheVerify(fastJwtSigned);
},
{ minSamples },
)
.add(
'@carbonteq/jwt',
() => {
client.verify(ctJwtSigned);
},
{ minSamples },
)
.add(
'@carbonteq/jwt#withCache',
() => {
cacheClient.verify(ctJwtSigned);
},
{ minSamples },
)
.on('cycle', function (e) {
console.log(String(e.target));
})
Expand Down
11 changes: 11 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,15 @@ export class JwtClient {
sign(data: Record<string, any>, expiresInSeconds: number, claimOpts?: ClaimOpts | undefined | null): string
signClaims(claims: Claims): string
verify(token: string): Claims
get header(): Header
}
export class JwtCacheClient {
constructor(secretKey: string | Buffer, ttlSecs: number, maxCapacity: number, opts?: JwtClientInitOpts | undefined | null)
static withPubPrivKeys(pubKey: string | Buffer, privKey: string | Buffer, ttlSecs: number, maxCapacity: number, opts?: JwtClientInitOpts | undefined | null): JwtCacheClient
sign(data: Record<string, any>, claimOpts?: ClaimOpts | undefined | null): string
verify(token: string): Claims
invalidateCache(): void
get header(): Header
get ttlSecs(): number
get maxCapacity(): number
}
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,9 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}

const { Algorithm, Claims, JwtClient } = nativeBinding
const { Algorithm, Claims, JwtClient, JwtCacheClient } = nativeBinding

module.exports.Algorithm = Algorithm
module.exports.Claims = Claims
module.exports.JwtClient = JwtClient
module.exports.JwtCacheClient = JwtCacheClient
26 changes: 23 additions & 3 deletions src/algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ pub enum Algorithm {
EdDSA,
}

impl Default for Algorithm {
fn default() -> Self {
Self::HS256
}
}

impl From<Algorithm> for jsonwebtoken::Algorithm {
#[inline]
fn from(value: Algorithm) -> Self {
Expand All @@ -49,8 +55,22 @@ impl From<Algorithm> for jsonwebtoken::Algorithm {
}
}

impl Default for Algorithm {
fn default() -> Self {
Self::HS256
impl From<jsonwebtoken::Algorithm> for Algorithm {
#[inline]
fn from(value: jsonwebtoken::Algorithm) -> Self {
match value {
jsonwebtoken::Algorithm::HS256 => Self::HS256,
jsonwebtoken::Algorithm::HS384 => Self::HS384,
jsonwebtoken::Algorithm::HS512 => Self::HS512,
jsonwebtoken::Algorithm::ES256 => Self::ES256,
jsonwebtoken::Algorithm::ES384 => Self::ES384,
jsonwebtoken::Algorithm::RS256 => Self::RS256,
jsonwebtoken::Algorithm::RS384 => Self::RS384,
jsonwebtoken::Algorithm::RS512 => Self::RS512,
jsonwebtoken::Algorithm::PS256 => Self::PS256,
jsonwebtoken::Algorithm::PS384 => Self::PS384,
jsonwebtoken::Algorithm::PS512 => Self::PS512,
jsonwebtoken::Algorithm::EdDSA => Self::EdDSA,
}
}
}
2 changes: 1 addition & 1 deletion src/claims.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub struct ClaimOpts {
}

#[napi]
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Claims {
pub data: Map<String, Value>,
/// Time after which the JWT expires (as UTC timestamp, seconds from epoch time)
Expand Down
29 changes: 14 additions & 15 deletions src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,17 @@ impl From<Header> for jsonwebtoken::Header {
}
}

// impl Default for Header {
// #[inline]
// fn default() -> Self {
// Self {
// algorithm: Some(Algorithm::HS256),
// content_type: None,
// json_key_url: None,
// key_id: None,
// x5_url: None,
// x5_cert_chain: None,
// x5_cert_thumbprint: None,
// x5t_s256_cert_thumbprint: None,
// }
// }
// }
impl From<&jsonwebtoken::Header> for Header {
fn from(value: &jsonwebtoken::Header) -> Self {
Self {
x5t_s256_cert_thumbprint: value.x5t_s256.clone(),
x5_cert_thumbprint: value.x5t.clone(),
x5_cert_chain: value.x5c.clone(),
x5_url: value.x5u.clone(),
algorithm: Some(value.alg.into()),
content_type: value.cty.clone(),
key_id: value.kid.clone(),
json_key_url: value.jku.clone(),
}
}
}
Loading

0 comments on commit 3d66fe2

Please sign in to comment.