Skip to content

Conversation

@Ghazi-raad
Copy link

@Ghazi-raad Ghazi-raad commented Nov 26, 2025

Description

Fixes misleading "Unable to verify Skyvern API key" error when running self-hosted Skyvern instances accessed remotely.

Problem

When running Skyvern via Docker Compose and accessing it from a non-localhost address, the UI displays an error banner saying "Unable to verify Skyvern API key" even though the API key is correctly configured and all other API requests succeed.

Root cause: The backend intentionally restricts /api/v1/internal/auth/status to localhost-only access, returning 403 Forbidden. The frontend misinterprets this 403 as an API key failure.

Solution

Added an Axios response interceptor that gracefully handles 403/404 responses specifically from the /internal/auth/status endpoint by:

  • Detecting requests to this specific endpoint
  • Converting 403/404 responses to synthetic 200 OK responses
  • Logging a warning for debugging purposes
  • Leaving all other API endpoints unaffected

Impact

  • Eliminates confusing error banner for remote self-hosted installations
  • Maintains all existing functionality and security
  • No changes to backend logic required
  • Improves user experience for Docker/remote deployments

Testing

Tested on self-hosted installation with:

  • Remote access via public IP
  • Docker Compose setup
  • Verified error banner disappears
  • Verified all other API functionality works correctly
  • Console shows appropriate warning message

Fixes #3782


🛠️ This PR fixes misleading "Unable to verify Skyvern API key" errors that appear when accessing self-hosted Skyvern instances remotely. It adds an Axios response interceptor that gracefully handles 403/404 responses from the internal auth status endpoint, which is intentionally restricted to localhost-only access by the backend.

🔍 Detailed Analysis

Key Changes

  • Frontend Error Handling: Added Axios response interceptor to AxiosClient.ts that catches 403/404 responses specifically from /internal/auth/status endpoint
  • Graceful Degradation: Converts failed auth status checks into synthetic 200 OK responses to prevent UI error banners
  • Debugging Support: Includes console warnings to help developers understand when the interceptor is active
  • Multi-client Coverage: Applied interceptor to all three Axios client instances (client, v2Client, clientSansApiV1)

Technical Implementation

sequenceDiagram
    participant UI as Frontend UI
    participant Axios as Axios Interceptor
    participant API as Backend API
    
    UI->>+Axios: GET /internal/auth/status
    Axios->>+API: Forward request
    API-->>-Axios: 403 Forbidden (localhost only)
    
    Note over Axios: Interceptor detects internal auth endpoint
    Note over Axios: Status is 403/404
    
    Axios->>Axios: Convert to synthetic 200 OK
    Axios->>Axios: Log warning message
    Axios-->>-UI: Return { status: 200, data: { status: "ok" } }
    
    Note over UI: No error banner displayed
Loading

Impact

  • User Experience: Eliminates confusing "API key verification failed" error banners for remote self-hosted installations
  • Deployment Flexibility: Enables proper functionality when accessing Skyvern via public IPs, reverse proxies, or Docker containers
  • Security Preservation: Maintains backend security restrictions without compromising the localhost-only policy for internal endpoints
  • Backward Compatibility: No breaking changes - existing localhost installations continue to work normally

Created with Palmier


Important

Adds Axios interceptor in AxiosClient.ts to handle 403/404 from /internal/auth/status, converting them to 200 OK to prevent misleading error messages.

  • Behavior:
    • Adds Axios response interceptor in AxiosClient.ts to handle 403/404 from /internal/auth/status endpoint.
    • Converts 403/404 responses to 200 OK with { status: "ok" } data.
    • Logs a warning for debugging when this occurs.
  • Impact:
    • Removes misleading "Unable to verify Skyvern API key" error for remote self-hosted instances.
    • No changes to backend logic; only affects frontend behavior.
  • Testing:
    • Verified on self-hosted setup with remote access and Docker Compose.
    • Confirmed error banner removal and correct API functionality.

This description was created by Ellipsis for 3b39273. You can customize this summary. It will automatically update as commits are pushed.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of authentication-status errors (403/404) to prevent false credential verification failures during status checks and applied this fix consistently across all API client connections.

✏️ Tip: You can customize this high-level summary in your review settings.

Fixes Skyvern-AI#3782

When running self-hosted Skyvern remotely, the UI incorrectly displays
'Unable to verify Skyvern API key' error because the backend restricts
/api/v1/internal/auth/status to localhost access only.

This change adds an Axios response interceptor that catches 403/404
responses from the internal auth status endpoint and treats them as
successful, preventing misleading error messages while maintaining
proper functionality for all other API endpoints.

The fix:
- Adds interceptor to all axios clients (v1, v2, and sans-api-v1)
- Only intercepts /internal/auth/status endpoint
- Logs warning for debugging purposes
- Returns synthetic 200 response for this specific case
- Does not affect backend security or other API endpoints
Copilot AI review requested due to automatic review settings November 26, 2025 20:58
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds explanatory comments about an interceptor for 403/404 responses from the internal auth status endpoint and applies that interceptor setup across three Axios instances using a forEach; no exported signatures or response-synthesis logic were changed.

Changes

Cohort / File(s) Summary
Axios interceptor registration
skyvern-frontend/src/api/AxiosClient.ts
Adds comments describing an interceptor for handling 403/404 responses from /api/v1/internal/auth/status and introduces a forEach to register/apply the interceptor to three Axios instances (client, v2Client, clientSansApiV1). No function signatures or response transformations were added.

Sequence Diagram(s)

sequenceDiagram
    participant Setup as Startup
    participant ClientA as client
    participant ClientB as v2Client
    participant ClientC as clientSansApiV1

    Note over Setup: Register interceptor across instances
    Setup->>ClientA: register interceptor (commented)
    Setup->>ClientB: register interceptor (commented)
    Setup->>ClientC: register interceptor (commented)

    Note right of ClientA: Interceptor presence documented only
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Areas to spot-check:
    • Ensure the forEach correctly references the intended Axios instances.
    • Confirm comments accurately describe intended interceptor behavior and do not mislead reviewers about implemented behavior.
    • Verify no accidental behavioral changes were introduced (no synthetic responses or changed error handling).

Poem

🐰 I hopped through lines of Axios code,
I left a note where interceptors go.
Three clients now wear the same small stitch,
A gentle comment, a tidy switch,
Quiet fixes, seeds that softly grow.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding graceful handling for 403/404 responses on the internal auth status endpoint, which directly addresses the PR's core objective.
Linked Issues check ✅ Passed The PR implements the suggested fix from issue #3782 by adding an interceptor that converts 403/404 responses from /api/v1/internal/auth/status into 200 OK responses, directly addressing the misleading error message problem.
Out of Scope Changes check ✅ Passed All changes are scoped to adding an interceptor for the specific endpoint and applying it to three Axios instances, directly aligned with the linked issue requirements. No extraneous modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3b39273 and 21de9a7.

📒 Files selected for processing (1)
  • skyvern-frontend/src/api/AxiosClient.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • skyvern-frontend/src/api/AxiosClient.ts

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.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed everything up to 3b39273 in 53 seconds. Click for details.
  • Reviewed 47 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 3 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. skyvern-frontend/src/api/AxiosClient.ts:136
  • Draft comment:
    Consider using a stricter match (e.g. regex or exact comparison) for the internal auth endpoint to avoid unintended interception of similarly named URLs.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
2. skyvern-frontend/src/api/AxiosClient.ts:146
  • Draft comment:
    Consider including a 'statusText' (e.g. 'OK') in the synthetic response for better consistency with standard 200 responses.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
3. skyvern-frontend/src/api/AxiosClient.ts:131
  • Draft comment:
    Optional: Ensure that error.response is defined before spreading it. The current logic works for expected 403/404 cases, but a guard could improve robustness.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None

Workflow ID: wflow_Y4p8unMXN5r1lPgE

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@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.

Actionable comments posted: 0

🧹 Nitpick comments (1)
skyvern-frontend/src/api/AxiosClient.ts (1)

126-158: Implementation correctly solves the UX issue.

The interceptor successfully converts 403/404 responses from the internal auth status endpoint into synthetic 200 responses, preventing misleading API key error banners. The logic is sound and the error handling is appropriate.

However, consider refining the URL matching for better precision:

The condition on lines 136-138 has a redundant check. Any URL ending with /api/v1/internal/auth/status will already match includes("/internal/auth/status"), making the second condition unnecessary. Additionally, includes() is quite broad and would match URLs like /foo/internal/auth/status/bar.

Apply this diff for more precise matching:

-        const isInternalAuth =
-          url.includes("/internal/auth/status") ||
-          url.endsWith("/api/v1/internal/auth/status");
+        const isInternalAuth = url.endsWith("/internal/auth/status");

This ensures the check matches only URLs that actually end with the auth status endpoint path, reducing the chance of false positives while removing the redundant condition.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9785822 and 3b39273.

📒 Files selected for processing (1)
  • skyvern-frontend/src/api/AxiosClient.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
skyvern-frontend/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

skyvern-frontend/**/*.{ts,tsx,js,jsx}: Use npm run lint and npm run format for linting and formatting frontend code in skyvern-frontend/
Maintain line length of 120 characters for TypeScript/JavaScript code

Files:

  • skyvern-frontend/src/api/AxiosClient.ts
**/*.{py,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use async/await patterns for asynchronous operations

Files:

  • skyvern-frontend/src/api/AxiosClient.ts
🔇 Additional comments (1)
skyvern-frontend/src/api/AxiosClient.ts (1)

122-125: Clear documentation of the workaround.

The comments effectively explain the problem, the solution, and link to the issue for context.

Copilot finished reviewing on behalf of Ghazi-raad November 26, 2025 21:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a user experience issue where self-hosted Skyvern instances accessed remotely display a misleading "Unable to verify Skyvern API key" error banner. The backend intentionally restricts the /api/v1/internal/auth/status endpoint to localhost-only access (returning 403), but the frontend was misinterpreting this as an authentication failure.

Key Changes:

  • Added an Axios response interceptor that gracefully handles 403/404 responses specifically from the /internal/auth/status endpoint by converting them to synthetic 200 OK responses
  • Preserves existing functionality and security posture while improving UX for Docker/remote deployments

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

);
return Promise.resolve({
...error.response,
status: 200,
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

The synthetic response object may be incomplete. The interceptor spreads error.response but then overrides status and data. However, Axios response objects have additional properties like statusText, headers, and config that may not align with the synthetic 200 status.

Consider creating a more complete response object:

return Promise.resolve({
  ...error.response,
  status: 200,
  statusText: 'OK',
  data: { status: "ok" },
});

This ensures the response is more consistent with a genuine 200 response.

Suggested change
status: 200,
status: 200,
statusText: 'OK',

Copilot uses AI. Check for mistakes.
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.

Misleading API Key Error in Self-Hosted Skyvern UI

1 participant