You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
description: Implement dynamic authentication patterns like short-lived JWT signing in your SDKs.
4
4
---
5
5
6
-
Your API may require dynamic authentication where credentials need to be generated or refreshed for each request, such as signing short-lived JWTs or rotating tokens. Fern-generated SDKs support this pattern through request-level header injection.
6
+
Your API may require dynamic authentication where credentials need to be generated or refreshed for each request, such as signing short-lived JWTs or rotating tokens. Fern-generated SDKs support this pattern through custom fetcher middleware.
7
7
8
-
## How it works
8
+
## Recommended: Custom fetcher middleware
9
9
10
-
Fern-generated SDKs accept a `headers` parameter in the `RequestOptions` for every API call. This allows you to inject dynamically computed headers (like signed JWTs) on a per-request basis without needing to override each method.
10
+
The best way to implement dynamic authentication in TypeScript SDKs is to use a custom fetcher. This acts as middleware for all requests, allowing you to inject authentication logic in a single place without overriding individual methods.
11
11
12
-
##TypeScript example: Short-lived JWT signing
12
+
### How it works
13
13
14
-
Here's how to implement a client wrapper that signs a JWT valid for 15 seconds before each request:
14
+
When you enable `allowCustomFetcher` in your generator configuration, the generated SDK accepts a `fetcher` parameter in the client options. This fetcher wraps all HTTP requests, giving you a single injection point for authentication logic.
15
+
16
+
### TypeScript example: Short-lived JWT signing
17
+
18
+
Here's how to implement JWT signing with token memoization:
15
19
16
20
<Steps>
17
21
18
-
### Create a wrapper client
22
+
### Enable custom fetcher in generator configuration
23
+
24
+
Add `allowCustomFetcher: true` to your `generators.yml`:
25
+
26
+
```yaml title="generators.yml"
27
+
default-group: local
28
+
groups:
29
+
local:
30
+
generators:
31
+
- name: fernapi/fern-typescript-node-sdk
32
+
version: 0.x.x
33
+
output:
34
+
location: local-file-system
35
+
path: ../generated/typescript
36
+
config:
37
+
allowCustomFetcher: true
38
+
```
39
+
40
+
### Create a custom fetcher with JWT signing
19
41
20
-
Create a custom client class that extends the generated Fern client and adds JWT signing logic:
42
+
Create a fetcher function that wraps the default fetcher and injects JWT authentication:
21
43
22
-
```typescript title="src/wrapper/MyClient.ts"
23
-
import { MyClientasFernClient } from"../Client";
44
+
```typescript title="src/wrapper/jwtFetcher.ts"
24
45
import * as jwt from "jsonwebtoken";
46
+
import { fetcher as defaultFetcher, type FetchFunction } from "../core/fetcher";
25
47
26
-
exportclassMyClientextendsFernClient {
27
-
private privateKey:string;
48
+
export function createJwtFetcher(privateKey: string): FetchFunction {
49
+
// Cache token to avoid regenerating on every request
50
+
let cachedToken: { value: string; expiresAt: number } | undefined;
This approach automatically wraps all methods without needing to override each one individually.
186
+
<Note>This approach requires overriding each method individually, which can be tedious for large APIs. The custom fetcher approach is recommended for better maintainability.</Note>
190
187
191
188
## Python example: Short-lived JWT signing
192
189
193
-
For Python SDKs, you can use a similar pattern:
190
+
For Python SDKs, you can use a similar method override pattern:
This same pattern works for other dynamic authentication scenarios:
234
231
235
232
-**OAuth token refresh**: Automatically refresh expired access tokens before each request
236
-
-**HMAC signing**: Sign requests with HMAC signatures based on request content
233
+
-**HMAC (Hash-based Message Authentication Code) signing**: Sign requests with HMAC signatures based on request content
237
234
-**Rotating API keys**: Switch between multiple API keys based on rate limits
238
235
-**Time-based tokens**: Generate tokens that include timestamps or nonces
239
236
240
-
## Best practices
237
+
## Important considerations
241
238
242
-
-**Cache when possible**: If your tokens are valid for longer periods, cache them to avoid regenerating on every request
243
-
-**Handle errors gracefully**: Implement retry logic for authentication failures
239
+
### Custom fetcher requirements
240
+
241
+
-**Generator configuration**: The `allowCustomFetcher` option must be enabled in your `generators.yml` for the `fetcher` parameter to be available in `BaseClientOptions`
242
+
-**Import path**: Import the default fetcher from `../core/fetcher` (or the appropriate path in your generated SDK) to wrap it with your custom logic
243
+
-**Preserve all arguments**: When wrapping the default fetcher, ensure you pass through all arguments to maintain compatibility with the SDK's internal behavior
244
+
245
+
### Security considerations
246
+
247
+
-**Server-side only**: Never expose private keys in browser environments. JWT signing with private keys should only be done in server-side code (Node.js, Deno, Bun)
244
248
-**Secure key storage**: Never hardcode private keys; use environment variables or secure key management systems
245
-
-**Test thoroughly**: Ensure your wrapper handles all edge cases, including concurrent requests
249
+
-**Avoid double authentication**: If your API already uses bearer token authentication in the Fern definition, be careful not to override the existing `Authorization` header. Consider using a different header name or conditionally setting the header
250
+
251
+
### Performance and concurrency
252
+
253
+
-**Token memoization**: Cache tokens to avoid regenerating them on every request. The example above caches tokens and refreshes them 2 seconds before expiration
254
+
-**Thread safety**: The memoization pattern shown is safe for concurrent requests in JavaScript's single-threaded event loop, but be mindful of race conditions in other environments
255
+
-**Grace period**: Refresh tokens slightly before they expire (e.g., 2 seconds early) to avoid edge cases where a token expires during request processing
256
+
257
+
### Header merging
258
+
259
+
-**Preserve existing headers**: When injecting authentication headers, always spread existing headers to avoid overwriting headers set by the SDK or user
260
+
-**Header precedence**: Headers are merged in order: SDK defaults → client options → request options → custom fetcher. Your custom fetcher runs last and can override previous headers
261
+
262
+
### Time synchronization
263
+
264
+
-**Clock drift**: Be aware of potential clock drift between your client and server. Consider adding tolerance to your token expiration checks
265
+
-**Timestamp precision**: Use Unix timestamps (seconds since epoch) for `iat` and `exp` claims to match JWT standards
266
+
267
+
## Best practices
268
+
269
+
-**Use custom fetcher for TypeScript**: The custom fetcher approach is the most maintainable solution for TypeScript SDKs when `allowCustomFetcher` is available
270
+
-**Cache tokens appropriately**: Balance between security (shorter token lifetime) and performance (less frequent regeneration)
271
+
-**Handle errors gracefully**: Implement retry logic for authentication failures and token refresh errors
272
+
-**Test thoroughly**: Ensure your wrapper handles all edge cases, including concurrent requests, token expiration, and network failures
273
+
-**Monitor token usage**: Log token generation and refresh events to help debug authentication issues in production
0 commit comments