Skip to content

Fix/explicit rpid config - #585

Merged
Miracle656 merged 4 commits into
Miracle656:mainfrom
Davoski1:fix/explicit-rpid-config
Sep 3, 2026
Merged

Fix/explicit rpid config#585
Miracle656 merged 4 commits into
Miracle656:mainfrom
Davoski1:fix/explicit-rpid-config

Conversation

@Davoski1

Copy link
Copy Markdown
Contributor

Summary

Supply the Relying Party ID (rpId) and origin explicitly in the wallet configuration so native builds do not fall back to localhost.

Changes

  • Update frontend/wallet/lib/network.ts
    • Add rpId and origin fields to walletConfig, read from NEXT_PUBLIC_RP_ID and NEXT_PUBLIC_ORIGIN.
  • Update examples/nextjs/src/lib/network.ts
    • Same environment-backed rpId / origin additions for the example app.

Why

Native apps (Expo / React Native) lack window.location.hostname, causing the SDK to default to localhost. That breaks passkey binding on real devices because the relying-party id must match the production domain. Reading rpId and origin from environment variables allows CI and device builds to set the correct production values without changing source.

Notes for maintainers / operators

  • Set NEXT_PUBLIC_RP_ID (e.g. veil.app) and NEXT_PUBLIC_ORIGIN (e.g. https://veil.app) in your environment/CI before building production artifacts.
  • Existing behavior is preserved when env vars are unset: the SDK will continue to resolve rpId/origin from window.location or its previous fallbacks.

Testing / Verification

  1. Build the app with NEXT_PUBLIC_RP_ID=veil.app and NEXT_PUBLIC_ORIGIN=https://veil.app set and verify walletConfig passed to useInvisibleWallet() contains those values.
  2. On a device, run register/authenticate flows and confirm passkeys are associated with the intended domain (not localhost).

Closes #442

@Davoski1
Davoski1 requested a review from Miracle656 as a code owner July 29, 2026 16:49
@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

@rhoggs-bot-test-account is attempting to deploy a commit to the miracle656's projects Team on Vercel.

A member of the Team first needs to authorize it.

@Miracle656

Copy link
Copy Markdown
Owner

Needs a rebase onto main. Two things drifted: the mobile config is now app.config.ts (not app.json/app.config.js), and both frontend/mobile/lib/network.ts and frontend/wallet/lib/network.ts have changed on main. Please rebase and move the explicit rpId config into the current app.config.ts / network files, then I'll take another look.

@Miracle656

Copy link
Copy Markdown
Owner

Apologies — this sat unreviewed for a month while main moved underneath it, and that is on us, not you.

What happened: PR #508 (3a9e337, "register veil:// scheme and universal/app links") landed after you opened this. It did the same job from the other direction:

  • Added associatedDomains to frontend/mobile/app.config.ts (line 56)
  • Added Android intentFilters with the assetlinks reference (lines 70–80)
  • Set bundleIdentifier, package and scheme
  • Deleted frontend/mobile/app.json

And the domain-association files are now hosted for real, not as examples:

frontend/wallet/public/.well-known/assetlinks.json
frontend/wallet/public/.well-known/apple-app-site-association

So the gap you were closing is closed. I have checked main rather than assuming.

One part of this is NOT superseded, and it is worth salvaging.

Your change to frontend/wallet/lib/network.ts:

rpId:   process.env.NEXT_PUBLIC_RP_ID?.trim() || undefined,
origin: process.env.NEXT_PUBLIC_ORIGIN?.trim() || undefined,

main has no equivalent — the only rpId handling is in lib/backup.ts, which falls back to window.location.hostname each time. So the config fields genuinely do not exist yet.

Two thoughts if you want to re-open it as a small focused PR:

  • The stated rationale — letting native builds supply the value — does not quite fit, since frontend/wallet is the web app and frontend/mobile has its own Expo config. But there is a better one: the wallet is served from app.useveilapp.xyz and from Vercel preview URLs. A passkey registered under one hostname will not resolve under the other, because rpId is the hostname. An explicit, pinned rpId is exactly how you stop that.
  • It is also a footgun worth documenting: setting NEXT_PUBLIC_RP_ID to a domain the page is not served from makes WebAuthn fail outright with a SecurityError. Defaulting to undefined, as you did, is the right call — the risk only appears if someone sets it wrong.

So: the three Expo/well-known files here are superseded, but those two lines are not. A PR with just them, plus a note in the env documentation about the preview-URL case, would land.

Not closing this. Sorry for the month.

…eded

Kept: explicit rpId and origin on walletConfig, sourced from
NEXT_PUBLIC_RP_ID / NEXT_PUBLIC_ORIGIN and undefined when unset, so the SDK's
window.location fallback still applies to the web build. Same addition in the
Next.js example.

Merged as a union with main rather than either side winning: the storage
adapter that Miracle656#659 added to walletConfig and these two fields are unrelated
additions to the same object literal.

Dropped frontend/mobile/app.config.js and examples/expo/.well-known/* -- the
same files this author's Miracle656#584 carried, and superseded for the same reasons.
main's app.config.ts already claims both applinks: and webcredentials: per
domain and carries the bundle id, intent filters, plugins and EAS project id;
a second Expo config alongside it is at best dead and at worst silently wins
and drops all of that. The real .well-known files under
frontend/wallet/public/ carry the actual package name and certificate
fingerprint.

Verified: wallet tsc clean, 17 of 18 suites passing (feeBump.test.ts fails
identically on main -- TextEncoder undefined in jsdom).

@Miracle656 Miracle656 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Approved and merging — rebased and reduced on your branch (59e51bb).

The change itself is right and I kept it as written. Explicit rpId and origin on walletConfig, from NEXT_PUBLIC_RP_ID / NEXT_PUBLIC_ORIGIN, defaulting to undefined when unset.

That last detail is what makes it safe: undefined leaves the SDK's window.location.hostname fallback intact, so the web build behaves exactly as before and only a deployment that opts in changes. Coercing to an empty string instead would have set the relying-party ID to '' on every existing deploy and broken WebAuthn everywhere — a one-character difference between a no-op and an outage.

The reason it's needed is worth stating plainly: on a native build there is no window.location to fall back to, so the relying-party ID has to come from configuration or the ceremony cannot name a relying party at all. Same addition in the Next.js example, which is the right place for a consumer to see it.

On the merge: walletConfig had gained a storage adapter from #659 since this branch was cut, so I resolved that as a union rather than letting either side win — two unrelated additions to one object literal, both wanted.

What I dropped: frontend/mobile/app.config.js and examples/expo/.well-known/*, the same files your #584 carried and superseded for the same reasons. main's app.config.ts already claims both applinks: and webcredentials: per domain and carries the bundle identifier, Android intent filters, plugins and EAS project id — a second Expo config beside it is at best dead, and at worst wins and silently drops all of that. Full reasoning on #584, which is merged.

Verified: wallet tsc --noEmit clean, 17 of 18 suites passing. The exception is feeBump.test.ts, which fails identically on main (TextEncoder is not defined in jsdom, from the stellar-sdk browser bundle) — checked against a stashed tree, not assumed.

Thanks.

@Miracle656
Miracle656 merged commit 72a1b55 into Miracle656:main Sep 3, 2026
7 of 13 checks passed
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.

14. Global error boundary + Sentry

2 participants