basquetWi + New ticket

Record browser context on sign-in and warn in-app browser users

Done normal ctcoder02-terra-cc

Elazar asked whether Terra can log the sign-in redirect chain, group attempts by IP, record the browser agent, and warn people who open the app inside WhatsApp the way ayudarg already does. Researched rather than assumed; this records what is possible, what is not, and the two decisions that belong to Elazar. Nothing has been built. WHAT TERRA ALREADY HAS. The flow is already correlated end to end: signInInitiated and signInCompleted share a flowId, and completion carries an outcome vocabulary of authorized, noProfile, providerFailed and lookupFailed. The missing piece in the 2026-08-30 incident was never correlation. It was that nothing recorded WHICH BROWSER opened the flow, so a question answerable in one query took a screenshot, a decoded timestamp and a day. WHAT CANNOT BE LOGGED, AND THIS BOUNDS THE WHOLE REQUEST. The chain Elazar described has a middle leg on accounts.google.com. No Terra code runs there, so that leg is unobservable to us in principle, not merely unimplemented. The incident died precisely on that leg: Google returned 400 on its own consent page and never called Terra back. A redirect logger, however good, would have recorded initiated and then silence - exactly what the rail already shows. It is still worth building, but it would not have explained this incident and must not be sold as if it would. THE CHEAP WIN. Record the user agent on signInInitiated, plus a boolean for embedded-browser detection. That single field is what turns fifteen hours of inference into one query, and it is the highest value item here by a wide margin. IP GROUPING NEEDS A RULING BEFORE ANY CODE. A raw IP address is personal data, and Terra has a standing rule that personal data never enters appEvents. A grouping key can be had without storing an address: either a salted hash of the IP, which groups attempts from one source without disclosing the source, or truncation to a network prefix. Both answer "was this the same network" while keeping the address out of the record. Which of the three - raw, hashed, truncated - is Elazar's decision, and no code should be written until it is made. THE WHATSAPP WARNING PORTS, WITH ONE ADAPTATION THAT MATTERS. ayudarg already ships this: a user-agent signature list covering WhatsApp, Instagram, Facebook, TikTok, WeChat and the Android system webview, checked server-side on the login page, surfacing guidance and never blocking a path. Terra can take the detector nearly verbatim. But ayudarg's primary advice is to fall back to e-mail and password, and TERRA HAS NO SUCH PATH - email sign-in is disabled and Google is the only door. So Terra's copy must offer the one remedy Terra actually has, which is to open the site in Chrome or Safari. The second half of ayudarg's pattern does not port at all. Its recovery page fires from the OAuth callback, when the PKCE verifier is missing. Terra's user never reached the callback, so an equivalent page would have stayed dark. For Terra the warning must be PREVENTIVE, on the login page before the click, because after the click Terra has no further opportunity to say anything. CORROBORATION. Google has blocked OAuth from embedded webviews since 2017, extended to a hard sign-in refusal in July 2023, and names messaging apps opening links in webviews as an affected case. Note the documented symptom is a 403 disallowed_useragent, which is NOT what this user saw, so the published behaviour supports the class without matching this instance. What was actually observed in their URL was authuser=unknown, meaning Google could resolve no account from its cookies in that browser context.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 6w ago
    parent=#3094
  • wi-cli-venus verified · 6w ago
    --body
  • wi-cli-venus verified · 6w ago
    AUDIT PASS on 998a486 (v0.30.20), post-push against origin/main. Six files, 115 insertions. Independently re-ran the suite in the shared tree: 408/408, matching the reported figure. All three conditions I set before the work started are met in the shipped source, verified by reading the diff rather than by the report. The raw user-agent is stored RAW at src/lib/auth-actions.ts, sliced to 512 and null-coalesced, alongside the inAppBrowser boolean - not classified into a closed vocabulary, which is what would have filed the next unrecognised webview as "other". The comment on it draws the right distinction: unlike Host it is trusted as nothing and decides nothing. The login notice omits ayudarg's email-and-password fallback sentence and names only Chrome and Safari, which is terra's only true remedy since external_email_enabled is false. And the detector suite carries real negative controls - full plain iOS Safari and Android Chrome strings - plus a near-miss per signature, so a detector that answered yes to everything would go red on 13 arms rather than pass a positives-only suite. THE COVERAGE BOUND THAT MATTERS, and it is not a defect in this commit: this may not fire on the incident that motivated it. The screenshot from TERRA-137 showed a "back to WhatsApp" banner over what looked like ordinary iOS Safari chrome, which is the signature of SFSafariViewController - WhatsApp handing the link to a real Safari instance rather than rendering it in an embedded webview. That instance sends the standard Safari user agent with no WhatsApp token in it, so the signature list has nothing to match. A web search for the iOS in-app browser's user agent was inconclusive: the strings that surface publicly are WhatsApp's link-preview FETCHER (WhatsApp/2.20.x CFNetwork/Darwin), which is a different client entirely, so this is stated as an unverified bound and not as a measurement. That is exactly why the userAgent field is the load-bearing half of this commit and the notice is the cheap half. The next person stopped at Google now leaves a row that says which browser opened the flow, and the answer either matches a signature or it does not - either way the question stops costing a day. Do not close TERRA-137 on this. TERRA-138's own scope is delivered. Not in scope and correctly absent, each for its own reason: no IP logging (Elazar rejected it - it would not have discriminated anything here), no redirect-chain logger (the middle hop is on accounts.google.com, unloggable in principle by terra), no /error-auth recovery page port (its trigger is a missing PKCE verifier at the callback, and this user never reached the callback, so the page would have stayed dark). Lint carries one pre-existing warning at src/app/informes/page.tsx:47, untouched by this commit and not attributable to it. (This event supersedes the empty verified event stamped 09:36:06Z, whose body arrived as the literal string --body: wi event takes the body POSITIONALLY as the third argument, not behind a --body flag, and the flag form is not rejected - it is stored. bwi events are append-only, so the empty one stays.)
  • wi-cli-venus completed · 6w ago
    Shipped 998a486 (v0.30.20) by coder-terra-ca, audited PASS post-push by coder02-terra-cc against origin/main with the suite re-run independently (408/408). Detector, preventive /login notice and the signInInitiated browser fields all landed as specified. The coverage bound - it may not fire on an iOS SFSafariViewController handoff - is recorded on the verified event and is NOT a defect in this commit; the raw userAgent field is what answers the question next time regardless.
feature
6w ago by wi-cli-venus
6w ago
2026-08-31 10:35