Skip to content

feat(client-ts): add axios dependency and refresh token interceptor#212

Open
BHOGALA-SRIKA wants to merge 3 commits into
roshankumar0036singh:mainfrom
BHOGALA-SRIKA:feature/axios-interceptor
Open

feat(client-ts): add axios dependency and refresh token interceptor#212
BHOGALA-SRIKA wants to merge 3 commits into
roshankumar0036singh:mainfrom
BHOGALA-SRIKA:feature/axios-interceptor

Conversation

@BHOGALA-SRIKA

@BHOGALA-SRIKA BHOGALA-SRIKA commented Jun 21, 2026

Copy link
Copy Markdown

Closes #178

Description

This PR introduces an automatic Axios refresh token interceptor to the TypeScript SDK. It intercepts outgoing requests to attach the bearer token and seamlessly catches 401 Unauthorized responses to trigger a token refresh via AuthClient.refresh().

Concurrent requests hitting a 401 while a refresh is already in progress are queued and replayed once the new token is acquired.

Changes

  • Created clients/ts/src/interceptor.ts containing the interceptor logic and request queuing.
  • Exported the interceptor from clients/ts/src/index.ts.
  • Updated clients/ts/package.json and package-lock.json to include axios as a dependency, as it is required for the interceptor functionality.

Verification

  • Ran npm run build successfully (CJS, ESM, and DTS builds all passed cleanly).
  • Ran npm test and verified all 20 existing unit tests continue to pass.

Summary by CodeRabbit

  • New Features

    • Added automatic token refresh capability with request/response interceptor support for improved authentication handling.
  • Chores

    • Added axios HTTP client and Node.js type definitions as SDK dependencies.

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement.

To sign, please post a comment on this PR with the following exact text:

I have read the CLA and agree to its terms


I have read the CLA and agree to its terms.


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@BHOGALA-SRIKA, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 32 minutes and 4 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1746831a-7e06-42e4-84c2-71e324998767

📥 Commits

Reviewing files that changed from the base of the PR and between 83d33a0 and db0c3b7.

📒 Files selected for processing (1)
  • clients/ts/src/interceptor.ts
📝 Walkthrough

Walkthrough

A new createAuthInterceptor factory function is added to the TypeScript client package. It wires Axios request and response interceptors on a provided AxiosInstance to attach Bearer tokens and handle 401 responses with deduplicated token refresh and queued request replay. axios is added as a runtime dependency and the interceptor is re-exported from the package root.

Changes

Axios Auth Interceptor

Layer / File(s) Summary
Package dependencies and public re-export
clients/ts/package.json, clients/ts/src/index.ts
Adds axios ^1.18.0 to dependencies, @types/node ^26.0.0 to devDependencies, and re-exports all interceptor exports from the package root index.
createAuthInterceptor implementation
clients/ts/src/interceptor.ts
Defines the internal pending-request queue type, initializes isRefreshing and failedQueue state, implements processQueue to drain queued requests on refresh success or failure, wires a request interceptor to set Authorization: Bearer <token>, and wires a response interceptor to detect 401s, deduplicate concurrent refresh attempts via isRefreshing/failedQueue, replay held requests with the new token, and call authClient.logout() on refresh failure.

Sequence Diagram

sequenceDiagram
  participant App
  participant AxiosInstance
  participant RequestInterceptor
  participant ResponseInterceptor
  participant AuthClient

  App->>AxiosInstance: outgoing HTTP request
  AxiosInstance->>RequestInterceptor: onRequest
  RequestInterceptor->>AuthClient: getAccessToken()
  AuthClient-->>RequestInterceptor: token (or null)
  RequestInterceptor-->>AxiosInstance: Authorization: Bearer token

  AxiosInstance-->>ResponseInterceptor: 401 response
  alt First 401 (isRefreshing = false)
    ResponseInterceptor->>ResponseInterceptor: set isRefreshing = true, _retry = true
    ResponseInterceptor->>AuthClient: refresh()
    AuthClient-->>ResponseInterceptor: new token
    ResponseInterceptor->>ResponseInterceptor: processQueue(null, newToken)
    ResponseInterceptor-->>AxiosInstance: replay original request
  else Concurrent 401 (isRefreshing = true)
    ResponseInterceptor->>ResponseInterceptor: push resolve/reject to failedQueue
    note over ResponseInterceptor: waits until processQueue drains
  end
  alt refresh() throws
    ResponseInterceptor->>ResponseInterceptor: processQueue(error, null)
    ResponseInterceptor->>AuthClient: logout()
    ResponseInterceptor-->>App: reject all queued + original requests
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 A rabbit hops through HTTP lanes,
Bearer tokens tucked beneath their mane.
When 401 wolves lurk in the night,
The queue holds steady, refresh in flight!
One retry rule, no infinite loops —
The burrow stays safe with interceptor troops. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main changes: adding axios dependency and implementing a refresh token interceptor for the TypeScript client.
Description check ✅ Passed The description provides a clear explanation of the changes, includes verification details, and references the closed issue. The CLA checklist is present though not checked off.
Linked Issues check ✅ Passed The pull request fully addresses issue #178 by implementing a createAuthInterceptor factory function that handles automatic token refresh and request queuing, making token refresh transparent to the application.
Out of Scope Changes check ✅ Passed All changes are directly related to the linked issue objectives: the interceptor implementation, exports, and dependency additions are all necessary for the token refresh feature.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
clients/ts/src/interceptor.ts (1)

9-84: ⚡ Quick win

Return interceptor IDs to enable cleanup.

The function registers interceptors but doesn't return their IDs, making it impossible to eject them later. This is useful for testing and for SPAs that need to clean up on unmount.

♻️ Proposed refactor to return cleanup function
-export function createAuthInterceptor(axiosInstance: AxiosInstance, authClient: AuthClient) {
+export function createAuthInterceptor(axiosInstance: AxiosInstance, authClient: AuthClient): () => void {
   let isRefreshing = false;
   let failedQueue: FailedRequestQueueItem[] = [];
   
   // ... processQueue definition ...

-  // 1. Request Interceptor: Attach the current token to outgoing requests
-  axiosInstance.interceptors.request.use(
+  const requestInterceptorId = axiosInstance.interceptors.request.use(
     // ... existing implementation ...
   );

-  // 2. Response Interceptor: Catch 401 errors and handle seamless token refreshes
-  axiosInstance.interceptors.response.use(
+  const responseInterceptorId = axiosInstance.interceptors.response.use(
     // ... existing implementation ...
   );
+
+  return () => {
+    axiosInstance.interceptors.request.eject(requestInterceptorId);
+    axiosInstance.interceptors.response.eject(responseInterceptorId);
+  };
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@clients/ts/src/interceptor.ts` around lines 9 - 84, The createAuthInterceptor
function does not return the interceptor IDs that are generated when registering
the request and response interceptors with axiosInstance. Modify the function to
capture the numeric IDs returned by both
axiosInstance.interceptors.request.use() and
axiosInstance.interceptors.response.use() calls, and return them (either as an
object or a cleanup function) so callers can later eject these interceptors
using axiosInstance.interceptors.request.eject() and
axiosInstance.interceptors.response.eject() methods. This enables proper cleanup
for testing and single-page applications that need to remove interceptors on
unmount.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@clients/ts/src/interceptor.ts`:
- Line 42: The `_retry` property being accessed on `originalRequest` does not
exist on Axios's `InternalAxiosRequestConfig` type, causing TypeScript
compilation errors. To fix this, augment the Axios request config type at the
top of the interceptor.ts file to include the `_retry` property as an optional
boolean field, which will allow TypeScript to recognize this custom property
when checking `originalRequest._retry` in the 401 error handling logic
(appearing at lines 42 and 58).
- Around line 13-22: The processQueue function does not handle the case where
both error is falsy and token is undefined, which leaves queued promises hanging
indefinitely. In the processQueue function, add an else branch after the else if
(token) condition to handle the case where neither an error nor a valid token is
provided (i.e., when token is undefined). When this occurs, reject all promises
in the failedQueue with an appropriate error indicating that the token refresh
failed or returned an invalid token, ensuring no promises remain pending.

---

Nitpick comments:
In `@clients/ts/src/interceptor.ts`:
- Around line 9-84: The createAuthInterceptor function does not return the
interceptor IDs that are generated when registering the request and response
interceptors with axiosInstance. Modify the function to capture the numeric IDs
returned by both axiosInstance.interceptors.request.use() and
axiosInstance.interceptors.response.use() calls, and return them (either as an
object or a cleanup function) so callers can later eject these interceptors
using axiosInstance.interceptors.request.eject() and
axiosInstance.interceptors.response.eject() methods. This enables proper cleanup
for testing and single-page applications that need to remove interceptors on
unmount.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c673b7bb-52bc-493b-96a9-d16f713d63f1

📥 Commits

Reviewing files that changed from the base of the PR and between 3b63188 and 83d33a0.

⛔ Files ignored due to path filters (1)
  • clients/ts/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • clients/ts/package.json
  • clients/ts/src/index.ts
  • clients/ts/src/interceptor.ts

Comment thread clients/ts/src/interceptor.ts
Comment thread clients/ts/src/interceptor.ts Outdated
@sonarqubecloud

Copy link
Copy Markdown

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.

Automatic Refresh Token Interceptor for Axios/Fetch

1 participant