Skip to content

Conversation

@omeraplak
Copy link
Member

@omeraplak omeraplak commented Dec 23, 2025

PR Checklist

Please check if your PR fulfills the following requirements:

Bugs / Features

What is the current behavior?

What is the new behavior?

fixes (issue)

Notes for reviewers


Summary by cubic

Introduces authNext, a new authentication policy that protects all routes by default and separates access into public, console, and user. Deprecates legacy auth while preserving backward compatibility, updates middleware and WebSocket handling, and refreshes docs and examples.

  • New Features

    • Added authNext with route access resolution (public → console → user) and configurable publicRoutes/consoleRoutes.
    • Default console routes cover management, docs, observability, updates, and console WebSockets; exported DEFAULT_CONSOLE_ROUTES.
    • New Hono middleware createAuthNextMiddleware; user context injection preserved.
    • WebSocket auth supports authNext, Console Access Key via header or ?key, and dev bypass via ?dev=true.
    • Console Access Key check now accepts query param (?key) in HTTP and WebSocket.
    • Re-exports in server-hono: DEFAULT_CONSOLE_ROUTES, createAuthNextMiddleware, AuthNextConfig.
    • Tests added for authNext route resolution and Hono custom route protection; docs rewritten to recommend authNext.
  • Migration

    • Switch to authNext: server: honoServer({ authNext: { provider: jwtAuth({ secret }), publicRoutes: [...] } }).
    • Set VOLTAGENT_CONSOLE_ACCESS_KEY in production; send x-console-access-key or use ?key=YOUR_KEY for console and WebSocket endpoints.
    • For development, use x-voltagent-dev: true (HTTP) or ?dev=true (WebSocket).
    • If customizing console coverage, provide consoleRoutes or extend DEFAULT_CONSOLE_ROUTES.
    • Legacy auth is deprecated; if both authNext and auth are set, authNext takes precedence and logs a warning.

Written for commit 8ca41ab. Summary will update automatically on new commits.

@changeset-bot
Copy link

changeset-bot bot commented Dec 23, 2025

🦋 Changeset detected

Latest commit: 8ca41ab

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@voltagent/server-core Patch
@voltagent/server-hono Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@joggrbot

This comment has been minimized.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 15 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/server-core/src/auth/utils.ts">

<violation number="1" location="packages/server-core/src/auth/utils.ts:75">
P1: Security: Passing access keys in URL query parameters exposes credentials to logging, browser history, Referer headers, and proxy caches. Sensitive authentication tokens should only be transmitted via headers (like the existing `x-console-access-key` header) or POST body, not in URLs. Consider removing query parameter authentication for production security.</violation>
</file>

<file name="packages/server-core/src/auth/next.ts">

<violation number="1" location="packages/server-core/src/auth/next.ts:79">
P2: Inconsistent route configuration behavior: `publicRoutes` merges config with provider routes, but `consoleRoutes` completely replaces defaults when provided. If a user sets `consoleRoutes: [&quot;/my-admin&quot;]`, they&#39;ll lose all DEFAULT_CONSOLE_ROUTES (like &quot;WS /ws&quot;, &quot;GET /api/logs&quot;, etc.). Consider merging instead: `const consoleRoutes = [...DEFAULT_CONSOLE_ROUTES, ...(config.consoleRoutes ?? [])];`</violation>
</file>

<file name="packages/server-core/src/websocket/setup.ts">

<violation number="1" location="packages/server-core/src/websocket/setup.ts:39">
P2: Empty block for dev bypass on protected routes leaves `user` as `null`. Consider setting a user object (e.g., `{ id: &quot;dev&quot;, type: &quot;dev-bypass&quot; }`) for consistency with the legacy flow, or add explicit documentation if leaving user as null is intentional.</violation>
</file>

<file name="packages/server-hono/src/auth/middleware.ts">

<violation number="1" location="packages/server-hono/src/auth/middleware.ts:124">
P2: Dev bypass doesn&#39;t apply to console routes, but error message suggests it does. If `hasConsoleAccess` fails, the middleware returns 401 before reaching the `isDevRequest` check. Consider adding the dev bypass check for console routes to match the error hint.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

// 2. Console Access Key check (for production)
const consoleKey = req.headers.get("x-console-access-key");
const url = new URL(req.url, "http://localhost");
const queryKey = url.searchParams.get("key");
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 23, 2025

Choose a reason for hiding this comment

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

P1: Security: Passing access keys in URL query parameters exposes credentials to logging, browser history, Referer headers, and proxy caches. Sensitive authentication tokens should only be transmitted via headers (like the existing x-console-access-key header) or POST body, not in URLs. Consider removing query parameter authentication for production security.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/server-core/src/auth/utils.ts, line 75:

<comment>Security: Passing access keys in URL query parameters exposes credentials to logging, browser history, Referer headers, and proxy caches. Sensitive authentication tokens should only be transmitted via headers (like the existing `x-console-access-key` header) or POST body, not in URLs. Consider removing query parameter authentication for production security.</comment>

<file context>
@@ -68,9 +71,11 @@ export function hasConsoleAccess(req: Request): boolean {
   // 2. Console Access Key check (for production)
   const consoleKey = req.headers.get(&quot;x-console-access-key&quot;);
+  const url = new URL(req.url, &quot;http://localhost&quot;);
+  const queryKey = url.searchParams.get(&quot;key&quot;);
   const configuredKey = process.env.VOLTAGENT_CONSOLE_ACCESS_KEY;
 
</file context>
Fix with Cubic

return "public";
}

const consoleRoutes = config.consoleRoutes ?? DEFAULT_CONSOLE_ROUTES;
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 23, 2025

Choose a reason for hiding this comment

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

P2: Inconsistent route configuration behavior: publicRoutes merges config with provider routes, but consoleRoutes completely replaces defaults when provided. If a user sets consoleRoutes: ["/my-admin"], they'll lose all DEFAULT_CONSOLE_ROUTES (like "WS /ws", "GET /api/logs", etc.). Consider merging instead: const consoleRoutes = [...DEFAULT_CONSOLE_ROUTES, ...(config.consoleRoutes ?? [])];

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/server-core/src/auth/next.ts, line 79:

<comment>Inconsistent route configuration behavior: `publicRoutes` merges config with provider routes, but `consoleRoutes` completely replaces defaults when provided. If a user sets `consoleRoutes: [&quot;/my-admin&quot;]`, they&#39;ll lose all DEFAULT_CONSOLE_ROUTES (like &quot;WS /ws&quot;, &quot;GET /api/logs&quot;, etc.). Consider merging instead: `const consoleRoutes = [...DEFAULT_CONSOLE_ROUTES, ...(config.consoleRoutes ?? [])];`</comment>

<file context>
@@ -0,0 +1,85 @@
+    return &quot;public&quot;;
+  }
+
+  const consoleRoutes = config.consoleRoutes ?? DEFAULT_CONSOLE_ROUTES;
+  if (matchesAnyRoute(method, path, consoleRoutes)) {
+    return &quot;console&quot;;
</file context>
Fix with Cubic

* Helper to check console access for WebSocket IncomingMessage
*/
function hasWebSocketConsoleAccess(req: IncomingMessage, url: URL): boolean {
if (isWebSocketDevBypass(req, url)) {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 23, 2025

Choose a reason for hiding this comment

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

P2: Empty block for dev bypass on protected routes leaves user as null. Consider setting a user object (e.g., { id: "dev", type: "dev-bypass" }) for consistency with the legacy flow, or add explicit documentation if leaving user as null is intentional.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/server-core/src/websocket/setup.ts, line 39:

<comment>Empty block for dev bypass on protected routes leaves `user` as `null`. Consider setting a user object (e.g., `{ id: &quot;dev&quot;, type: &quot;dev-bypass&quot; }`) for consistency with the legacy flow, or add explicit documentation if leaving user as null is intentional.</comment>

<file context>
@@ -21,34 +23,30 @@ function isDevWebSocketRequest(req: IncomingMessage): boolean {
+ * Helper to check console access for WebSocket IncomingMessage
+ */
+function hasWebSocketConsoleAccess(req: IncomingMessage, url: URL): boolean {
+  if (isWebSocketDevBypass(req, url)) {
     return true;
   }
</file context>
Fix with Cubic

Comment on lines +124 to +125
if (access === "console") {
if (hasConsoleAccess(c.req.raw)) {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 23, 2025

Choose a reason for hiding this comment

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

P2: Dev bypass doesn't apply to console routes, but error message suggests it does. If hasConsoleAccess fails, the middleware returns 401 before reaching the isDevRequest check. Consider adding the dev bypass check for console routes to match the error hint.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/server-hono/src/auth/middleware.ts, line 124:

<comment>Dev bypass doesn&#39;t apply to console routes, but error message suggests it does. If `hasConsoleAccess` fails, the middleware returns 401 before reaching the `isDevRequest` check. Consider adding the dev bypass check for console routes to match the error hint.</comment>

<file context>
@@ -127,3 +99,138 @@ export function createAuthMiddleware(authProvider: AuthProvider&lt;Request&gt;) {
+      return next();
+    }
+
+    if (access === &quot;console&quot;) {
+      if (hasConsoleAccess(c.req.raw)) {
+        return next();
</file context>
Suggested change
if (access === "console") {
if (hasConsoleAccess(c.req.raw)) {
if (access === "console") {
if (hasConsoleAccess(c.req.raw) || isDevRequest(c.req.raw)) {
Fix with Cubic

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Dec 23, 2025

Deploying voltagent with  Cloudflare Pages  Cloudflare Pages

Latest commit: 8ca41ab
Status: ✅  Deploy successful!
Preview URL: https://9536fef2.voltagent.pages.dev
Branch Preview URL: https://feat-auth-next.voltagent.pages.dev

View logs

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="website/docs/api/authentication.md">

<violation number="1" location="website/docs/api/authentication.md:84">
P2: Documentation inconsistency: Route Access Summary shows &#39;Console key or JWT&#39; for Observability/Updates in legacy auth, but the Legacy section states only &#39;Console Access Key&#39; is required. This contradiction could cause users to misconfigure authentication for observability endpoints.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

| Management | `GET /agents`, `GET /workflows`, `GET /tools` | Console key | Public |
| Docs + UI | `GET /`, `GET /doc`, `GET /ui` | Console key | Public |
| Discovery | `GET /mcp/servers`, `GET /agents/:id/card` | Console key | Public |
| Observability | `/observability/*`, `GET /api/logs`, `WS /ws/observability/**` | Console key | Console key or JWT |
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 23, 2025

Choose a reason for hiding this comment

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

P2: Documentation inconsistency: Route Access Summary shows 'Console key or JWT' for Observability/Updates in legacy auth, but the Legacy section states only 'Console Access Key' is required. This contradiction could cause users to misconfigure authentication for observability endpoints.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At website/docs/api/authentication.md, line 84:

<comment>Documentation inconsistency: Route Access Summary shows &#39;Console key or JWT&#39; for Observability/Updates in legacy auth, but the Legacy section states only &#39;Console Access Key&#39; is required. This contradiction could cause users to misconfigure authentication for observability endpoints.</comment>

<file context>
@@ -48,6 +48,48 @@ new VoltAgent({
+| Management     | `GET /agents`, `GET /workflows`, `GET /tools`                                   | Console key                 | Public             |
+| Docs + UI      | `GET /`, `GET /doc`, `GET /ui`                                                  | Console key                 | Public             |
+| Discovery      | `GET /mcp/servers`, `GET /agents/:id/card`                                      | Console key                 | Public             |
+| Observability  | `/observability/*`, `GET /api/logs`, `WS /ws/observability/**`                  | Console key                 | Console key or JWT |
+| Updates        | `GET /updates`, `POST /updates`, `POST /updates/:packageName`                   | Console key                 | Console key or JWT |
+| Custom routes  | `GET /health`, `POST /webhooks/*`                                               | User token (JWT) by default | Public by default  |
</file context>
Fix with Cubic

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 23, 2025

Choose a reason for hiding this comment

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

I've fixed the documentation inconsistency in the Route Access Summary table. The table previously showed "Console key or JWT" for Observability and Updates endpoints under Legacy auth, but the Legacy section (line 612) clearly states that these endpoints "require Console Access Key in production" with no JWT alternative.

Change made:

  • Updated lines 84-85 in the Route Access Summary table to show "Console key" instead of "Console key or JWT" for both Observability and Updates under the Legacy auth Access column

This aligns the table with the authoritative description in the Legacy section, preventing users from incorrectly assuming JWT authentication would work for observability endpoints when using legacy auth.

PR: #885

@omeraplak omeraplak merged commit 9320326 into main Dec 23, 2025
22 checks passed
@omeraplak omeraplak deleted the feat/auth-next branch December 23, 2025 16:28
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.

3 participants