Skip to content

Fix auth token check#6

Merged
Ehsan-saradar merged 3 commits intomainfrom
fix/auth-token-check
Feb 19, 2026
Merged

Fix auth token check#6
Ehsan-saradar merged 3 commits intomainfrom
fix/auth-token-check

Conversation

@Ehsan-saradar
Copy link
Contributor

@Ehsan-saradar Ehsan-saradar commented Feb 18, 2026

Fix #5

Summary by CodeRabbit

  • New Features

    • Implemented automatic token refresh on session expiration (401 responses)
    • Added automatic re-authentication attempts with user notification when sessions expire
    • Improved session state management to prevent stale data during authentication flows
  • Bug Fixes

    • Enhanced error handling for network and unauthorized responses

@vercel
Copy link

vercel bot commented Feb 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
developer-portal Ready Ready Preview, Comment Feb 19, 2026 10:40am

Request Review

@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

Walkthrough

The changes implement automatic token refresh on 401 responses in the API client and establish a re-authentication workflow in the Core provider. When a token expires, failed requests are queued, an unauthorized handler obtains a new token, and queued requests are retried with the refreshed credentials.

Changes

Cohort / File(s) Summary
Token Refresh Infrastructure
src/api/client.ts
Added UnauthorizedHandler type, setUnauthorizedHandler registration function, request queuing during token refresh, and response interceptor logic to detect 401 responses, trigger a single token refresh, and retry queued requests with the new token.
Re-authentication Handler
src/providers/Core.tsx
Registered unauthorized handler via sessionRef that reads current session state, warns user of expired token, attempts re-authentication with signed message, and updates or clears session state based on success or failure.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Fix auth token check' is generic and vague, not clearly summarizing the main change of implementing automatic token refresh and re-authentication on 401 responses. Use a more descriptive title that clearly indicates the core change, such as 'Implement automatic token refresh on 401 responses' or 'Add global unauthorized handler for token expiration'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The changes implement automatic re-authentication on token expiration by introducing a global 401 handler that refreshes tokens and retries requests, directly addressing issue #5's requirement to automatically prompt for sign-in when tokens expire.
Out of Scope Changes check ✅ Passed All changes are directly focused on implementing token refresh and unauthorized handling; no out-of-scope modifications detected outside the linked issue objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/auth-token-check

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
src/api/client.ts (2)

47-73: Potential infinite retry loop if the refreshed token is immediately invalid.

When the retried request at line 71 receives another 401, the handler will be invoked again since _skipUnauthorizedHandler is not set on the retry. This could cause repeated re-auth attempts if the server keeps rejecting the new token.

Consider marking the retried request to skip the handler on subsequent failures:

🛡️ Proposed fix to prevent infinite retry
       }).then((token) => {
         error.config.headers["Authorization"] = `Bearer ${token}`;
+        error.config._skipUnauthorizedHandler = true;
         return apiClient(error.config);
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/api/client.ts` around lines 47 - 73, The retry logic can cause an
infinite loop because the retried request sent by apiClient(error.config)
doesn't set _skipUnauthorizedHandler, so another 401 will re-enter the same
flow; to fix, when resolving and retrying the queued requests set a flag on the
request config (e.g., error.config._skipUnauthorizedHandler = true) before
calling apiClient, so references to isRefreshing, unauthorizedHandler,
failedRequestsQueue and apiClient remain and you only mark the retried
request(s) to skip the handler to prevent repeated refresh attempts.

104-108: Consider skipping the unauthorized handler for the authenticate call.

The authenticate function is used during the re-authentication flow in the unauthorized handler. If the /auth endpoint ever returns a 401 (e.g., due to server misconfiguration), it would trigger recursive handler invocation.

🛡️ Proposed fix to prevent recursive refresh
 export const authenticate = async (
   data: AuthRequest,
 ): Promise<AuthResponse> => {
-  const response = await apiClient.post<AuthResponse>("/auth", data);
+  const response = await apiClient.post<AuthResponse>("/auth", data, {
+    _skipUnauthorizedHandler: true,
+  } as any);
   return response.data;
 };

Alternatively, declare the custom config property via module augmentation to avoid as any:

declare module 'axios' {
  interface InternalAxiosRequestConfig {
    _skipUnauthorizedHandler?: boolean;
  }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/api/client.ts` around lines 104 - 108, The authenticate function can
trigger the unauthorized handler recursively if the /auth call returns 401;
update authenticate to call apiClient.post with a request config that marks the
request to skip the unauthorized handler (e.g., set a custom flag like
_skipUnauthorizedHandler) so the global handler ignores this refresh attempt,
and optionally add the module augmentation for axios InternalAxiosRequestConfig
to declare _skipUnauthorizedHandler?: boolean to avoid using any casts;
reference authenticate and apiClient.post to implement this change.
src/providers/Core.tsx (1)

49-85: Consider extracting the duplicate message creation logic.

The nonce/expiry/message construction (lines 61-68) duplicates the logic in connect() (lines 119-129). Extracting this into a shared helper would reduce duplication and ensure consistency.

♻️ Example helper extraction
const createAuthMessage = (address: string) => {
  const nonce = hexlify(randomBytes(16));
  const expiryTime = new Date(Date.now() + 15 * 60 * 1000).toISOString();
  return JSON.stringify({
    message: "Sign into Vultisig Developer Portal",
    nonce,
    expiresAt: expiryTime,
    address,
  });
};

Then use createAuthMessage(address) in both the unauthorized handler and connect().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/Core.tsx` around lines 49 - 85, Extract the duplicated
nonce/expiry/message construction into a shared helper (e.g., createAuthMessage)
and replace the inline logic in both the setUnauthorizedHandler callback and the
connect() function with a call to that helper; ensure the helper returns the
exact JSON string used for signing so calls in setUnauthorizedHandler and
connect continue to pass the returned value into personalSign and authenticate
unchanged, and update any references to use the new helper name
(createAuthMessage) to keep nonce and expiresAt generation consistent across
setUnauthorizedHandler and connect.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/api/client.ts`:
- Around line 47-73: The retry logic can cause an infinite loop because the
retried request sent by apiClient(error.config) doesn't set
_skipUnauthorizedHandler, so another 401 will re-enter the same flow; to fix,
when resolving and retrying the queued requests set a flag on the request config
(e.g., error.config._skipUnauthorizedHandler = true) before calling apiClient,
so references to isRefreshing, unauthorizedHandler, failedRequestsQueue and
apiClient remain and you only mark the retried request(s) to skip the handler to
prevent repeated refresh attempts.
- Around line 104-108: The authenticate function can trigger the unauthorized
handler recursively if the /auth call returns 401; update authenticate to call
apiClient.post with a request config that marks the request to skip the
unauthorized handler (e.g., set a custom flag like _skipUnauthorizedHandler) so
the global handler ignores this refresh attempt, and optionally add the module
augmentation for axios InternalAxiosRequestConfig to declare
_skipUnauthorizedHandler?: boolean to avoid using any casts; reference
authenticate and apiClient.post to implement this change.

In `@src/providers/Core.tsx`:
- Around line 49-85: Extract the duplicated nonce/expiry/message construction
into a shared helper (e.g., createAuthMessage) and replace the inline logic in
both the setUnauthorizedHandler callback and the connect() function with a call
to that helper; ensure the helper returns the exact JSON string used for signing
so calls in setUnauthorizedHandler and connect continue to pass the returned
value into personalSign and authenticate unchanged, and update any references to
use the new helper name (createAuthMessage) to keep nonce and expiresAt
generation consistent across setUnauthorizedHandler and connect.

@Ehsan-saradar Ehsan-saradar merged commit df4047c into main Feb 19, 2026
7 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.

Automatically prompt for sign in again if token expires

1 participant