ReviewOS
@if (!issue)

No such issue

stacks/wildloop has no issue numbered 970.

@else

stacks/wildloop

OAuth social login (Google/Apple)

#970
Closed glennmichael123 opened this 9 days ago ·
9 days ago

Problem

login.stx and register.stx both render two social buttons with full provider artwork, and neither does anything: no @click, no OAuth routes, no provider config. A visitor who presses one gets no feedback at all.

They are Google and Apple — not GitHub, as this issue said until now. login.stx:190 and :196, register.stx:261 and :267. Nothing in app/Actions/Auth/ handles a callback; the only GitHub OAuth in the codebase is Actions/Buddy/BuddyGitHubConnectAction, which is buddy-bot's repository connection and unrelated to signing in.

Worth knowing before this is picked up: Apple is the more demanding half. Sign in with Apple needs a paid developer account, a Services ID, a key rather than a secret, a client secret regenerated on a schedule, and — if we ever ship the iOS app to the App Store offering any other social login — it is required rather than optional. Google alone is a much smaller piece of work, and shipping it first is reasonable.

Acceptance

  • OAuth redirect and callback routes, with provider config from env.
  • Wire both buttons; create or link a user on first login.
  • User.password nullable, for accounts that only ever authenticate through a provider.
  • Decide what happens when a provider returns an email that already has a password account — link or refuse, not a silent second account.
  • A signed-out visitor who presses a button and abandons the flow lands back where they started, still signed out, with no half-created user.
9 days ago

Google is built and live on wildloop.org. Apple is not started.

Shipped in 7a3eee30, 0c9cc27c, 046620de, 88ed3d5f, a9857148:

  • GET /api/auth/google/redirect → GET /api/auth/google/callback → POST /api/auth/google/session
  • user_identities, keyed on the provider subject rather than the address, because a Google account's address can change and the person is the same person when it does
  • Both the sign-in and sign-up buttons wired; the round trip returns to whichever page it began on
  • Production credentials set and deployed — the redirect now answers 302 to accounts.google.com

Against the acceptance list:

  • Redirect and callback routes, provider config from env
  • Both buttons wired; create or link a user on first sign-in
  • User.password nullable — solved differently, see below
  • An address that already has a password account is linked, and only when Google says it verified the address itself
  • An abandoned flow leaves no half-created user: the account is created after a successful token exchange, never before

The password column deviates from what this issue asked for, on purpose. users.password is NOT NULL in every database — generated from the model's own required() rule, despite the committed migration saying otherwise — and SQLite cannot relax a column without rebuilding the table, which is not a thing to do to a live users table for tidiness. So an account created this way gets 32 random bytes, hashed, plaintext discarded unread. Nobody can sign in with a password because there is no password to type, and the framework already refuses a falsy stored password by substituting a dummy hash. "Forgot password" still works, so somebody who signed up with Google can add one later.

Still open, and the reason this issue stays open:

  • Apple. Needs a paid developer account, a Services ID, a key rather than a secret, and a client secret regenerated on a rotation. It also becomes required by App Store rules once the iOS app ships with any other third-party sign-in, so it is a "before the app ships" item rather than a never.
  • The consent screen is in testing mode. Only accounts on its test-user list can complete a sign-in, whatever the code does.
  • No sign-in has completed anywhere. user_identities has no rows. The token exchange, the create-or-link decision, the session and the hand-off have never executed against a real Google response — only the decisions behind them are covered, by 22 tests that need no network.
9 days ago

The native app has no Google button, and it is not a configuration mistake.

Found while reproducing #1007 on a simulator against the bundled build. The static build bakes the sign-in page out:

$ grep -oE "Or continue with|Signing in with Apple|auth/google/redirect" dist/login.html
  Or continue with
  Signing in with Apple      <- Apple is there
                             <- Google is not

So