Conversation
Wire the dashboard to Ory through Auth.js while preserving Supabase mode behind the auth provider switch.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryHigh Risk Overview Auth.js / Ory client flow: New Server auth integration: Dashboard API (OpenAPI): Adds bearer + team security schemes on existing routes, admin profile resolve/lookup endpoints, and Local Hydra provider routes: Note for reviewers: Some client features (e.g. terminal / sandbox inspect) still obtain tokens via Reviewed by Cursor Bugbot for commit 8f3504b. Bugbot is set up for automated code reviews on this repo. Configure here. |
| loginChallenge: challenge, | ||
| }) | ||
|
|
||
| const { redirect_to } = await hydra.acceptOAuth2LoginRequest({ |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: HIGH
The login provider route accepts any login_challenge and unconditionally authenticates it as a fixed ORY_LOCAL_LOGIN_SUBJECT, but there is no runtime enforcement that this path can only run in local/dev mode.
If this route is ever wired outside an isolated dev setup, an attacker can start an OAuth flow and receive tokens as that fixed subject, resulting in authentication bypass/account impersonation.
| className="text-fg underline underline-offset-[3px]" | ||
| > | ||
| Continue if you are not redirected automatically | ||
| </button> |
There was a problem hiding this comment.
Raw button element instead of Button primitive
Low Severity
A new raw <button> element with manual Tailwind styling (text-fg underline underline-offset-[3px]) is used instead of the Button component from @/ui/primitives/button. This is new feature code that violates the rule requiring use of the Button primitive for consistent focus rings, disabled states, and accessibility.
Triggered by learned rule: Use Button primitive instead of raw button elements
Reviewed by Cursor Bugbot for commit 95f62c7. Configure here.
| name: keyof OryTokenClaims | ||
| ): string | null { | ||
| return readStringClaim(claims, name) | ||
| } |
There was a problem hiding this comment.
readRequiredStringClaim is identical to readStringClaim
Low Severity
readRequiredStringClaim is a wrapper that does nothing beyond calling readStringClaim — it returns string | null without enforcing any "required" semantics. The name is misleading: callers reading the code at line 29 (readRequiredStringClaim(accessClaims, 'sub')) would expect it to throw or assert on missing claims, but it silently returns null just like the non-required variant.
Reviewed by Cursor Bugbot for commit 95f62c7. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 95f62c79a9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const isOry = isOryAuthEnabled() | ||
| const headers: Record<string, string> = isOry | ||
| ? { Authorization: `Bearer ${token}` } |
There was a problem hiding this comment.
Avoid server-only env checks in shared auth header helper
authHeaders now switches behavior via isOryAuthEnabled(), which reads process.env.AUTH_PROVIDER, but this helper is also consumed by client-side code paths introduced in this commit (for example terminal/inspect browser SDK calls). In Next.js, non-NEXT_PUBLIC_ env vars are not available in browser bundles, so client code will not reliably select the Ory branch and can keep emitting Supabase-style headers; in AUTH_PROVIDER=ory deployments that causes sandbox API calls from the browser to be unauthorized.
Useful? React with 👍 / 👎.
Wire the dashboard as Hydra's login provider so the OIDC flow can complete end-to-end against a self-hosted Hydra (e.g. ../infra devenv) without requiring a separate IdP UI. - src/app/oauth/login: auto-accept login challenges as ORY_LOCAL_LOGIN_SUBJECT. - src/app/oauth/consent: defensive auto-accept (never hit while the seeded client has skip_consent=true; kept for misconfiguration safety). - src/app/oauth/logout: auto-accept logout challenges. - src/core/server/auth/ory/hydra-admin.ts: OAuth2Api client that targets ORY_HYDRA_ADMIN_URL (self-hosted, no PAT) or ORY_SDK_URL (Ory Network, PAT). - src/lib/env.ts: new optional ORY_HYDRA_ADMIN_URL and ORY_LOCAL_LOGIN_SUBJECT. - package.json: pin 'next dev' to :3001 so it doesn't collide with the infra api on :3000 and matches the seeded client's redirect_uri. Modeled on ory/hydra-login-consent-node. Intended for local/dev only; production deployments delegate login to Ory Network / Kratos.
Cookies are scoped by host+path+name, not port, so multiple local dashboards on different localhost ports shared the default authjs.session-token cookie and clobbered each other's sessions. AUTH_COOKIE_PREFIX lets each instance use a distinct cookie name; unset in prod/preview keeps the standard name.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
There are 6 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8f3504b. Configure here.
|
|
||
| const userId = data.session.user.id | ||
| const headers = SUPABASE_AUTH_HEADERS(data.session.access_token, teamId) | ||
| const headers = authHeaders(data.session.access_token, teamId) |
There was a problem hiding this comment.
Terminal still uses Supabase session
High Severity
With AUTH_PROVIDER=ory, the dashboard terminal and sandbox inspect flows still load credentials via supabase.auth.getSession(), while API calls use authHeaders() and send a Bearer Ory access token. There is no Supabase session in Ory mode, so connect/create fails or users are sent back to sign-in despite an active Auth.js session.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 8f3504b. Configure here.
| } | ||
|
|
||
| const proxyWithOryAuth = authjsMiddleware(async (req, _event: NextFetchEvent) => | ||
| proxyCore(req, !!req.auth) |
There was a problem hiding this comment.
Middleware ignores session error state
Medium Severity
In Ory mode, middleware treats any truthy req.auth as authenticated, but oryAuthProvider.getAuthContext() returns null when session.error is set (e.g. refresh failure) or when accessToken is missing. Users can keep accessing protected routes while server code treats them as signed out.
Reviewed by Cursor Bugbot for commit 8f3504b. Configure here.
| if (teamId) { | ||
| headers[isOry ? AUTH_PROVIDER_TEAM_HEADER : SUPABASE_TEAM_HEADER] = teamId | ||
| } | ||
| return headers |
There was a problem hiding this comment.
Client cannot detect Ory mode
High Severity
authHeaders() chooses Bearer vs Supabase headers via isOryAuthEnabled(), which reads process.env.AUTH_PROVIDER. That variable is not exposed to the browser bundle, so client code (terminal, sandbox inspect) always takes the Supabase branch even when the deployment runs AUTH_PROVIDER=ory.
Reviewed by Cursor Bugbot for commit 8f3504b. Configure here.
| typeof returnTo === 'string' && returnTo.length > 0 | ||
| ? returnTo | ||
| : '/dashboard' | ||
| await signIn('ory', { redirectTo }) |
There was a problem hiding this comment.
Ory sign-in skips returnTo validation
Medium Severity
signInWithOryAction forwards the form returnTo field straight to Auth.js signIn('ory', { redirectTo }) with no relativeUrlSchema check. Supabase sign-in/up flows validate returnTo the same way; the Ory hosted redirect hidden input is user-controlled.
Reviewed by Cursor Bugbot for commit 8f3504b. Configure here.


No description provided.