feat(auth): native-app sign-in handoff via one-time code - #66
Open
rigwig wants to merge 1 commit into
Open
Conversation
Native clients can't read the session cookie out of the system browser, so
today an app has to embed a web view for the OIDC flow and scrape the cookie.
That rules out passkeys (WebKit doesn't expose WebAuthn to embedded views for
third-party origins) and is the embedded-OAuth pattern Google discourages.
Add an opt-in handoff, disabled unless NATIVE_APP_SCHEMES is set:
- a native app opens the normal login page with a returnTo on one of its
registered URL schemes, e.g. /login?returnTo=jetpilot://auth;
- after sign-in, /oidc/callback redirects there with a single-use code
(5 minutes, kept in memory like activeConnections) and clears the browser
session so nothing is left behind in the system browser;
- POST /auth/exchange { code } establishes a regular session cookie.
Native returnTo URLs are only honoured on the plain sign-in path; the
device-adoption path (deviceId) is unchanged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related: #7, #46, jetkvm/kvm#650, jetkvm/kvm#520
Summary
Adds an opt-in way for native apps to sign in through the system browser instead of an embedded web view. Today the only way a native client can get a cloud session is to run the OIDC flow inside a WKWebView and scrape the cookie — which rules out passkeys (WebKit doesn't expose WebAuthn to embedded views for third-party origins like accounts.google.com) and is the embedded-OAuth pattern Google discourages. Disabled unless
NATIVE_APP_SCHEMESis set, so hosted behaviour is unchanged until you opt in.Flow
${APP_HOSTNAME}/login?returnTo=jetpilot://authin the system browser (ASWebAuthenticationSessionon iOS, Custom Tabs on Android). The existing login page already forwardsreturnTointo the form, so no frontend change is needed./oidc/callbacksees areturnToon a registered scheme, redirects tojetpilot://auth?code=…with a single-use code (5-minute TTL, in-memory likeactiveConnections), and clears the browser session so nothing is left behind in Safari.POST /auth/exchangewith{ "code": "…" }and stores thesession/session.sigcookies from the response. From there it's an ordinary session.Native
returnToURLs are honoured only on the plain sign-in path; the device-adoption path (deviceId) is untouched.Notes for review
returnTotoAPP_HOSTNAME; once either lands I'll rebase so the validation accepts "same origin or registered native scheme". Together they close Open redirect via returnTo #7 while enabling this./auth/exchangesetauthenticatedAtas well.NATIVE_APP_SCHEMES=jetpiloton the hosted instance; happy to coordinate a test against staging.Checklist
npm run buildandnpm testpass locally (8 new tests intest/native-auth.test.ts: scheme allowlist on/off, single-use codes,/auth/exchangesuccess and failure modes).env.exampledocument the settingContext: I maintain JetPilot, an iOS client for JetKVM. Users regularly ask why Google passkeys don't work in the in-app sign-in; this is the server half of fixing that.