Skip to content

Conversation

@zhengzheng-jason
Copy link
Contributor

@zhengzheng-jason zhengzheng-jason commented Nov 6, 2025

Problem

After refactoring RefX auth model from a static API key to dynamic JWT token, we need to implement this JWT signing logic in SDK so less effort needed at the caller side.

Closes REFX-590

Solution

Reference: https://buildwithfern.com/learn/sdks/generators/typescript/dynamic-authentication

By referencing Fern documentation, this PR extended the default client to implement a ReferralExchangeJwtClient with customised fetcher. The customised fetcher can help sign a JWT token and then utilised the default fetcher to finish up the call. This extended client uses jwtwebtoken to sign the JWT hence added this new dependency.

why do we need a src/browser/jsonwebtoken-stub.ts

jsonwebtoken uses Node-only crypto module and can fail yarn & yarn test because it checks browser compatibility, as by design(Fern) the SDK should be able to be used in web env as well. However, this JWT client should only be used in server hence added a stub so browser bundles stay lean and predictable. The stub throws a descriptive error at runtime to make it clear the JWT client isn’t meant for browsers, while Node builds continue to use the real library.

why add .fernignore

To avoid the extended client being overridden by auto generation

Tests

Published an alpha version in NPM and tested the SDK in HAS locally. Tested the new client calls RefX successfully. In RefX server we can see it passed the new auth guard.

Deploy Notes

NA

@linear
Copy link

linear bot commented Nov 6, 2025

@socket-security
Copy link

socket-security bot commented Nov 6, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​types/​jsonwebtoken@​9.0.101001007382100
Updated@​types/​readable-stream@​4.0.22 ⏵ 4.0.181001007587100
Updatedreadable-stream@​4.7.0 ⏵ 4.6.099 +110010083 -1100
Updatedts-loader@​9.5.4 ⏵ 9.5.199 +110010083 -1100
Addedjsonwebtoken@​9.0.29910010083100
Updatedwebpack@​5.102.1 ⏵ 5.97.196 +110010093100
Updatedts-jest@​29.4.5 ⏵ 29.1.197 +11009493 +2100

View full report

.fernignore Outdated
# Specify files that shouldn't be modified by Fern

src/wrapper
src/index.ts
Copy link

Choose a reason for hiding this comment

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

if we ignore index.ts does this mean in the future if we for e.g. create a new error type it won't automatically be included by fern?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point lemme discuss with Fern side

Copy link
Contributor Author

Choose a reason for hiding this comment

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

confirmed with Fern that src/index.ts won't be touched by codegen. I changed to use wildcard for error types.


public async getToken(): Promise<string> {
const nowSeconds = Math.floor(Date.now() / 1000);
if (this.cachedToken != null && nowSeconds < this.cachedToken.expiresAtEpochSeconds - 1) {
Copy link

Choose a reason for hiding this comment

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

nit: can turn this into a constant, maybe TOKEN_CACHE_BUFFER_SECONDS or something

Wonder if the performance benefit is worth the possibility of returning expired tokens. When we call SmartCMS now we don't cache the JWTs im pretty sure. ofc we call them less often than for eg HAS calls RefX

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The current implementation signs a new token if the last token valid time is less than 1s, hence the client itself should not return expired token. However, this means the returned token TTL can vary from 1s ~ 15s. In case of the network, if the request spend more than 1s reaching RefX server, the token with 1s TTL might be expired.
To mitigate that, we might change the refresh buffer to be 5s, meaning returned token TTL can vary from 5s - 15s, giving more buffer to tolerate bad network.
Lemme know your thoughts!

Copy link

Choose a reason for hiding this comment

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

Yeah I was worried about 1s of network latency. 5s is safer for sure, but at some point I started wondering what the sweet spot is or if we should even do this optimisation HAHAH. But yeah honestly I don’t think network is likely to take 5s

Copy link
Contributor Author

Choose a reason for hiding this comment

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

got it yeah I double checked data dog and HAS -> RefX is roughly <100 request per min, i.e. <1.6 QPS. Even with Bright it's still very small scale hence performance impact should be very minor.
I will make the cached token configurable so we can start with no cache and fine tune it if we really hit a certain scale in NRP.

@zhengzheng-jason zhengzheng-jason merged commit d1819ca into master Nov 18, 2025
9 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.

2 participants