Skip to content

fix: split login page for Steward-only auth + Privy mock context#448

Open
0xSolace wants to merge 2 commits intodevfrom
fix/steward-login-split
Open

fix: split login page for Steward-only auth + Privy mock context#448
0xSolace wants to merge 2 commits intodevfrom
fix/steward-login-split

Conversation

@0xSolace
Copy link
Copy Markdown
Collaborator

Summary

Fixes the login page hanging when Steward auth is enabled without Privy credentials.

Changes

1. Split login page into isolated components

  • steward-login-section.tsx — Self-contained steward auth (passkey + email). Zero Privy imports.
  • privy-login-section.tsx — All existing Privy code moved here. Loaded via next/dynamic with ssr: false.
  • page.tsx — Slim orchestrator with 3 modes: steward-only, both, privy-only.

2. Privy mock context

When NEXT_PUBLIC_STEWARD_AUTH_ENABLED=true and Privy isn't configured, PrivyProvider wraps children with a dummy app ID so usePrivy() hooks return {ready: true, authenticated: false} instead of hanging.

Why

The login page imported usePrivy, useLogin, useLoginWithEmail, useLoginWithOAuth at the top level. Without a configured Privy app ID, these hooks hang forever showing a loading spinner. Now the Privy section is dynamically imported and never loaded when unconfigured.

Breaking Changes

  • None — existing Privy auth works exactly as before when configured

Follows #446 and #447.

Co-authored-by: wakesync shadow@shad0w.xyz

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 12, 2026

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

Project Deployment Actions Updated (UTC)
eliza-cloud Error Error Apr 12, 2026 0:03am
eliza-cloud-v2 Ready Ready Preview, Comment Apr 12, 2026 0:03am

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 12, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 68490508-6fca-48e9-8151-27145f144f3e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/steward-login-split

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.

0xSolace and others added 2 commits April 12, 2026 11:54
When NEXT_PUBLIC_STEWARD_AUTH_ENABLED is true and no valid Privy app ID
is configured, render PrivyProviderReactAuth with a dummy app ID instead
of bare fragments. This gives child components calling usePrivy() a
valid context (returning unauthenticated defaults) rather than throwing
due to missing provider.

Co-authored-by: wakesync <shadow@shad0w.xyz>
When NEXT_PUBLIC_STEWARD_AUTH_ENABLED=true and no Privy app ID is set,
the login page now loads only the Steward login section via next/dynamic.
Privy hooks (usePrivy, useLogin, etc.) are never imported or executed.

- Created steward-login-section.tsx: self-contained StewardProvider + StewardLogin
- Created privy-login-section.tsx: all Privy hooks and OAuth/email/wallet logic
- Rewrote page.tsx: env-based conditional rendering with dynamic(() => import(), { ssr: false })
- Three modes: steward-only, both (steward first + divider + privy), privy-only (default)

Co-authored-by: wakesync <shadow@shad0w.xyz>
@0xSolace 0xSolace force-pushed the fix/steward-login-split branch from 402ac43 to 201bee5 Compare April 12, 2026 11:55
@claude
Copy link
Copy Markdown

claude bot commented Apr 12, 2026

Code Review

The refactoring approach is sound — using next/dynamic with ssr: false to isolate Privy hooks is the right fix for the hanging login page. The three-mode orchestrator in page.tsx is clean and easy to reason about. A few issues worth addressing:


Bug: Unused import in privy-login-section.tsx

LandingHeader is imported but never rendered in the component (it's now rendered by GradientBackground in page.tsx):

// privy-login-section.tsx line ~13 — dead import
import LandingHeader from "@/packages/ui/src/components/layout/landing-header";

This will likely cause a lint/build warning and should be removed.


Risk: Dummy Privy appId behavior is not guaranteed

In PrivyProvider.tsx, when Steward auth is enabled without Privy configured, the PR wraps children with a real PrivyProviderReactAuth using a hardcoded fake appId:

<PrivyProviderReactAuth appId="cm00000000000000000000000" config={privyConfig}>

The comment claims hooks will return {ready: true, authenticated: false}, but this depends on Privy's undocumented behavior with an unknown appId. An invalid appId could:

  • Cause Privy to remain in a ready: false state (reintroducing the hang)
  • Generate noisy network requests to Privy's servers
  • Break silently if Privy changes how it handles invalid IDs

Since PrivyLoginSection is now dynamically imported and never mounted in steward-only mode, the simpler <>{children}</> passthrough from before is actually sufficient — any component calling usePrivy() outside the login page should be audited separately. If the mock context is needed for some other call site, that should be documented with a comment explaining which component requires it.


Code duplication: getSafeReturnTo

This helper is defined identically in both privy-login-section.tsx and steward-login-section.tsx. Extract it to a shared utility (e.g., app/login/utils.ts) to avoid drift.


Type suppression: as any cast

// steward-login-section.tsx
client={new StewardClient({ baseUrl: STEWARD_AUTH_BASE_URL }) as any}

as any here hides whatever the actual type mismatch is. If StewardClient doesn't satisfy the expected client prop type, that's worth a proper fix or a typed cast with a comment explaining the incompatibility.


Redundant || undefined

// steward-login-section.tsx
const STEWARD_TENANT_ID = process.env.NEXT_PUBLIC_STEWARD_TENANT_ID || undefined;
// ...
tenantId={STEWARD_TENANT_ID || undefined}

STEWARD_TENANT_ID is already undefined when the env var is unset, so the second || undefined is a no-op. Just use tenantId={STEWARD_TENANT_ID}.


Minor: Footer inconsistency between modes

In steward-only mode, the Terms/Privacy footer is rendered explicitly in page.tsx. In privy-only and both modes, the footer is rendered inside PrivyLoginSection. This means footer placement is subtly different between modes and could drift independently. Consider moving the footer to GradientBackground or making it a shared prop so all modes behave consistently.


Pre-existing: Missing try/catch in send/verify handlers

handleSendCode and handleVerifyCode in privy-login-section.tsx call await sendCode()/await loginWithCode() without try/catch. If these throw, setLoadingButton(null) is never reached and the button stays stuck. This is carried over from the original file but now lives in an isolated component that's easier to fix.

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.

1 participant