feat(mobile-sso): serve assetlinks.json + App Links redirect allowlist #81

Merged
whitlocktech merged 1 commits from feat/mobile-app-links into main 2026-07-20 23:57:55 +00:00
Member

Server side of Android App Links (M9 follow-up — see docs/android/APP_LINKS.md, docs PR stacked separately). Additive; the mobile SSO bridge already on main is untouched except for one allowlist branch.

What

  • GET /.well-known/assetlinks.json at the web root (before the SPA catch-all), gated by the new admin setting mobile_app_links_enabled (default off → 404; on-but-no-fingerprint → 404). Emits the Digital Asset Links statement for the fixed published package (MOBILE_APP_PACKAGE, default com.runicgateway.app) + MOBILE_APP_CERT_SHA256 fingerprint(s) (comma-separated for cert rotation).
  • Redirect-URI allowlist: /auth/mobile/sso/start additionally accepts this shard's own self-origin https://<host>/mobile/callback only when App Links are enabled — one additive exact-match entry derived from APP_BASE_URL/request origin (never client input); the custom-scheme allowlist is never narrowed. Non-https redirects short-circuit the settings lookup so custom-scheme rejections stay fast.
  • settings.isMobileAppLinksEnabled() (fail-closed), getPublic().mobileAppLinks, admin updateSettings boolean validation, seed default off.

Why the app side is a separate, build-time opt-in

Android autoVerify needs a literal host at build time, so a single multi-tenant APK can't verify open-ended shard domains. This server route is correct for any App-Links-capable build; the app-side filter is a white-label/first-party opt-in. Full rationale in docs/android/APP_LINKS.md.

Tests

test/appLinks.test.js (route gating + allowlist accept/reject). Full suite: 284 pass / 0 fail. Swagger unchanged (the web-root verification file is #swagger.ignored — not part of the API surface).


🤖 AI-assisted: authored with Claude Code (Opus 4.8); commits carry a Co-Authored-By: Claude trailer.

🤖 Generated with Claude Code

Server side of Android **App Links** (M9 follow-up — see `docs/android/APP_LINKS.md`, docs PR stacked separately). Additive; the mobile SSO bridge already on `main` is untouched except for one allowlist branch. ## What - **`GET /.well-known/assetlinks.json`** at the web root (before the SPA catch-all), gated by the new admin setting **`mobile_app_links_enabled`** (default **off → 404**; on-but-no-fingerprint → 404). Emits the Digital Asset Links statement for the fixed published package (`MOBILE_APP_PACKAGE`, default `com.runicgateway.app`) + `MOBILE_APP_CERT_SHA256` fingerprint(s) (comma-separated for cert rotation). - **Redirect-URI allowlist:** `/auth/mobile/sso/start` additionally accepts this shard's own self-origin `https://<host>/mobile/callback` **only when App Links are enabled** — one *additive* exact-match entry derived from `APP_BASE_URL`/request origin (never client input); the custom-scheme allowlist is never narrowed. Non-https redirects short-circuit the settings lookup so custom-scheme rejections stay fast. - `settings.isMobileAppLinksEnabled()` (fail-closed), `getPublic().mobileAppLinks`, admin `updateSettings` boolean validation, seed default off. ## Why the app side is a separate, build-time opt-in Android `autoVerify` needs a **literal host at build time**, so a single multi-tenant APK can't verify open-ended shard domains. This server route is correct for *any* App-Links-capable build; the app-side filter is a white-label/first-party opt-in. Full rationale in `docs/android/APP_LINKS.md`. ## Tests `test/appLinks.test.js` (route gating + allowlist accept/reject). **Full suite: 284 pass / 0 fail.** Swagger unchanged (the web-root verification file is `#swagger.ignore`d — not part of the API surface). --- 🤖 AI-assisted: authored with **Claude Code** (Opus 4.8); commits carry a `Co-Authored-By: Claude` trailer. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
wtclaude added 1 commit 2026-07-20 23:38:19 +00:00
feat(mobile-sso): serve assetlinks.json + App Links redirect allowlist
All checks were successful
PR Checks / server-tests (pull_request) Successful in 9m23s
PR Checks / client-build (pull_request) Successful in 10m6s
PR Checks / bot-install (pull_request) Successful in 9m16s
bcc96e7cfb
Add the server side of Android App Links (M9 follow-up, docs/android/APP_LINKS.md):

- GET /.well-known/assetlinks.json at the web root, gated by the new admin
  setting `mobile_app_links_enabled` (default off -> 404; on-but-no-fingerprint
  -> 404). Emits the Digital Asset Links statement for the fixed published
  package (MOBILE_APP_PACKAGE) + MOBILE_APP_CERT_SHA256 fingerprint(s).
- mobileSso `/start` additionally accepts this shard's own self-origin
  https://<host>/mobile/callback when App Links are enabled — one additive
  exact-match entry, derived from APP_BASE_URL/request origin, never client
  input; the custom-scheme allowlist is never narrowed. The settings lookup is
  short-circuited for non-https redirects so custom-scheme rejections stay fast.
- settings.isMobileAppLinksEnabled() (fail-closed) + getPublic().mobileAppLinks;
  admin updateSettings validates the boolean; seed default off.

Tests: test/appLinks.test.js (route gating + allowlist). Full suite 284 pass.
Swagger unchanged (web-root verification file is #swagger.ignore'd).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NgyHnrNa8WwG3doxvxjuCr
whitlocktech approved these changes 2026-07-20 23:42:59 +00:00
whitlocktech scheduled this pull request to auto merge when all checks succeed 2026-07-20 23:43:05 +00:00
whitlocktech merged commit dacc1bd4f7 into main 2026-07-20 23:57:55 +00:00
whitlocktech deleted branch feat/mobile-app-links 2026-07-20 23:57:56 +00:00
Sign in to join this conversation.
No description provided.