Skip to content

Re-enable Phantom Connect in prod once Portal approves the app #1017

Description

@Potolski

Status

Phantom Connect is disabled in production. NEXT_PUBLIC_PHANTOM_APP_ID has been removed from the Vercel production environment so the "Continue with Phantom" button does not render.

Why it was disabled

The button was live and reaching Phantom, but Phantom rejected every attempt:

Auth2 /login/start request failed (400). Bad Request

The app submission was rejected because the domain-verification TXT record took too long to propagate. The DNS record (_phantom_portal-challenge) now resolves correctly, so the app can be resubmitted — but until Portal approves it, /login/start will keep 400ing and the button is a dead end for learners.

How it is disabled

No code change. The integration was built with an env-var gate:

  • getPhantomAppId() returns null for unset or whitespace-only (lib/phantom/config.ts)
  • createPhantomClient() then returns null
  • the provider's enabled stays false — no SDK, no listeners, no traffic (phantom-connect-provider.tsx:70)
  • the modal button is behind {phantomEnabled && …} (auth-modal.tsx:195)

To re-enable

  1. Confirm the app is approved in Phantom Portal, and that the allowed-domains list contains the production origin and http://localhost:3000 for dev.
  2. Set NEXT_PUBLIC_PHANTOM_APP_ID=d12abb45-9120-4e3c-a5f7-c8e0ad9842c3 in Vercel Production.
  3. Redeploy with build cache disabled. NEXT_PUBLIC_* is inlined at build time, so a cache-reusing redeploy silently keeps the old bundle. This bit us when disabling it — the variable was removed and the app id was still present in the served chunk afterwards.
  4. Verify from outside:
    curl -sL https://st.academy/en \
      | grep -o '/_next/static/chunks/[^"]*\.js' | sort -u \
      | while read c; do curl -sL "https://st.academy$c" \
          | grep -q d12abb45 && echo "present in $c"; done
  5. Do a real sign-in and confirm /login/start returns 200, not 400.

Blocks / related

Note

The settings graduation card is deliberately not behind this gate — it renders on prefs.walletProvider === "phantom-embedded", so any learner who already received an embedded wallet keeps the "take your wallet with you" instructions. Since sign-in never succeeded in production, that set is expected to be empty.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:authLaunch-experience workstreamarea:frontendNext.js frontendblocked:needs-humanNeeds a human decision or manual/infra action; not loop-codeable

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions