Add federated (Google/Facebook/Amazon) POTA sign-in via hosted-UI OAuth#161
Merged
Conversation
The SRP email+password path can only authenticate accounts that have a Cognito password. POTA users who sign in with Google / Facebook / Login-with-Amazon are federated identities with no pool password, so SRP fails for them with no in-app recourse. Add the Cognito hosted-UI authorization-code + PKCE flow, which covers every login method POTA offers (the managed login page presents email, Google, Facebook and Amazon together). It produces an ordinary refresh token, so the existing idToken()/refreshIdToken() + /adif upload path is unchanged downstream. POTA's Cognito app client registers exactly one redirect URI (https://pota.app/) and rejects custom schemes / localhost, so Chrome Custom Tabs can't intercept the code. A WebView we control can: it watches navigation and lifts ?code= out the instant Cognito redirects, before pota.app loads. The default WebView UA ("; wv") trips Google's disallowed_useragent block, so the WebView uses a plain Chrome UA. - PotaAuth: newPkce()/authorizeUrl()/exchangeCode() + token-endpoint POST and id_token email-claim parsing for display. - PotaOAuthLogin.kt (new): full-screen WebView dialog driving the flow. - PotaScreen: "Sign in with Google / Facebook / Amazon" button in the existing login dialog hands off to the WebView; success resumes the pending upload. assembleDebug green. Live federated round-trip still needs on-device verification with a real federated pota.app account. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a federated OAuth (hosted-UI) sign-in path for POTA uploads so users who authenticate via Google/Facebook/Amazon (no Cognito password → SRP fails) can still obtain a refresh token and proceed with in-app uploads.
Changes:
- Added Cognito hosted-UI OAuth2 authorization-code + PKCE support in
PotaAuth(authorize URL, code exchange, refresh-token persistence). - Introduced a full-screen WebView dialog to run the hosted-UI flow and capture the redirect code.
- Updated the existing POTA login dialog to offer a “Sign in with Google / Facebook / Amazon” path.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| ft8cn/app/src/main/res/values/strings_compose.xml | Adds strings for the new “or” separator and hosted-UI sign-in UI. |
| ft8cn/app/src/main/kotlin/radio/ks3ckc/ft8us/ui/pota/PotaScreen.kt | Adds a federated sign-in button and hooks it to the new hosted-UI WebView flow. |
| ft8cn/app/src/main/kotlin/radio/ks3ckc/ft8us/ui/pota/PotaOAuthLogin.kt | New full-screen WebView dialog to drive hosted-UI login, capture code=, and exchange for tokens. |
| ft8cn/app/src/main/kotlin/radio/ks3ckc/ft8us/pota/PotaAuth.kt | Implements PKCE generation, hosted-UI authorize URL, token exchange, and email-claim extraction for display. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| url: String, | ||
| ): Boolean = handleRedirect(url) | ||
| } | ||
| loadUrl(PotaAuth.authorizeUrl(pkce)) |
Comment on lines
+107
to
+110
| // Plain Chrome UA (no "; wv") so Google's consent screen loads. | ||
| settings.userAgentString = | ||
| "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 " + | ||
| "(KHTML, like Gecko) Chrome/125.0.0.0 Mobile Safari/537.36" |
# Conflicts: # ft8cn/app/src/main/kotlin/radio/ks3ckc/ft8us/pota/PotaAuth.kt
- Load the authorize URL from removeAllCookies' callback so the OAuth page only navigates once cookies are cleared (removeAllCookies is async; the eager loadUrl could reuse a stale session). - Strip only the "; wv" token from the device default WebView UA instead of hard-coding an Android 14 / Pixel 8 / Chrome 125 string that ages out; "; wv" is what Google rejects (disallowed_useragent). - Extract the UA logic to a testable stripWebViewToken() helper and cover it with StripWebViewTokenTest. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #161 +/- ##
==========================================
+ Coverage 6.37% 6.49% +0.12%
- Complexity 681 685 +4
==========================================
Files 269 271 +2
Lines 30979 31416 +437
Branches 4856 4958 +102
==========================================
+ Hits 1974 2040 +66
- Misses 28864 29235 +371
Partials 141 141
🚀 New features to boost your workflow:
|
This was referenced Jun 8, 2026
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.
What
Adds federated sign-in (Google / Facebook / Login-with-Amazon) to the in-app POTA log upload from #154. Stacked on
feat/pota-upload-spike— review the OAuth commit only.Why
The spike's login is Cognito
USER_SRP_AUTH— email + password. SRP can only authenticate accounts that have a Cognito password. POTA users who sign in "with Google" (or Facebook / Amazon) are federated identities with no pool password, so SRP fails for them and there's no in-app way forward. This closes that gap.How POTA's auth is configured (reverse-engineered)
https://parksontheair.auth.us-east-2.amazoncognito.com(from the pool's/.well-known/openid-configuration+ pota.app's JS bundle).openid email phone profile.https://pota.app/. Custom schemes,localhost, and any other path returnredirect_mismatch.Approach — and why WebView, not Custom Tabs
Because the sole redirect URI is POTA's own web domain, Chrome Custom Tabs can't intercept the code (claiming
https://pota.app/would needassetlinks.jsonon POTA's server). A WebView we control can: it watches navigation and lifts?code=out the instant Cognito redirects, before pota.app actually loads. Then it exchanges code→tokens with PKCE at/oauth2/token.The flow produces an ordinary Cognito refresh token, so everything downstream —
idToken(),refreshIdToken(),PotaClient.uploadAdif()— is unchanged. Federated login only fills in that first token.Google WebView caveat: the default Android WebView UA contains
; wv, which Google's consent screen rejects (disallowed_useragent). The WebView uses a plain Chrome UA so Google sign-in loads. Facebook / Amazon / email work either way.Changes
PotaAuth.kt—newPkce(),authorizeUrl(),exchangeCode()(token-endpoint POST + refresh-token persistence), andemail-claim parsing from the ID token for display. Samepota_authSharedPreferences and ID-token cache as the SRP path.PotaOAuthLogin.kt(new) — full-screenPotaOAuthDialogWebView that drives the hosted-UI flow, captures the redirect, and runs the exchange (spinner while exchanging). Clears cookies per attempt so the user can choose an account.PotaScreen.kt— an "or … Sign in with Google / Facebook / Amazon" button in the existing login dialog; success resumes the pending upload. Native email/password dialog untouched.strings_compose.xml— 3 new strings.Status / scope
assembleDebugis green. As with the parent spike, the live federated round-trip is unverified — it needs a real Google/Facebook/Amazon-backed pota.app account on a device (the WebView-UA-vs-Google behavior especially only confirms on-device).Follow-ups:
EncryptedSharedPreferencesmigration still pending there.🤖 Generated with Claude Code