Skip to content

feat(auth): phone+PIN primary + Google/Apple sign-in, email-OTP signup (W8) - #7

Merged
tedtadesse merged 1 commit into
developfrom
feature/w8-phone-pin-social-auth
Jul 22, 2026
Merged

feat(auth): phone+PIN primary + Google/Apple sign-in, email-OTP signup (W8)#7
tedtadesse merged 1 commit into
developfrom
feature/w8-phone-pin-social-auth

Conversation

@tedtadesse

Copy link
Copy Markdown
Collaborator

Makes phone the primary credential and adds social sign-in, so clients offer three options: phone+PIN, Google, Apple.

What's in it

  • Phone+PIN signup with an emailed OTP (EmailVerification + email_service) — no SMS provider, so the phone is stored canonical-but-unproven (phone_verified_at stays NULL, no verified phone identity). Proving the mailbox ≠ proving the handset.
  • registerWithPhone validates number/PIN/uniqueness before spending the single-use code (reset_pin rule).
  • signInWithPhonePin — generic, timing-equalised, rate-limited per IP + number.
  • setMyPhone — the phone a Google/Apple signup collects (unverified, no PIN; distinct from OTP-backed linkPhone).
  • signInWithGoogle / signInWithApple — verify the provider's RS256 ID token (accounts/social.py, PyJWT JWKS, audience pinned to configured client IDs), then reuse the anti-takeover sign_in_with_identity. No new dep beyond cryptography.
  • authCapabilities: phoneSignIn now = phone+PIN (always true); Google/Apple true only when client IDs are configured.

Tests / gates

  • 404 tests, 0 failures under CI config (SMS_BACKEND=disabled); +26 new (accounts/test_w8_auth.py). Ruff clean, no migration drift, authorization-policy test green.

Ops before enabling

  • SMTP for support@zazatechnologies.com (OTP delivery); GOOGLE_OAUTH_CLIENT_IDS / APPLE_CLIENT_IDS to switch social on.

🤖 Generated with Claude Code

…p (W8)

Make phone the primary credential and add social sign-in, so clients offer
three options: phone+PIN, Google, Apple.

- Signup proves the person with an EMAILED code (EmailVerification +
  email_service), not SMS — there is still no SMS provider — so the phone is
  stored canonical-but-unproven: phone_verified_at stays NULL and no verified
  phone identity is written. Proving the mailbox is not proving the handset.
- registerWithPhone: validate (number/PIN/uniqueness) BEFORE spending the
  single-use code, so a weak PIN or duplicate does not burn it (reset_pin rule).
- signInWithPhonePin: generic, timing-equalised, rate-limited per IP + number.
- setMyPhone: the phone a Google/Apple signup collects, UNVERIFIED and no PIN
  (distinct from linkPhone, which spends an OTP and marks the number proven).
- signInWithGoogle / signInWithApple: verify the provider's RS256 ID token in
  accounts/social.py (PyJWT PyJWKClient; audience pinned to configured client
  IDs — the anti-forgery control), then reuse identity.sign_in_with_identity
  (email is never used to match an account). No new dependency beyond
  cryptography, which PyJWT needs for RS256.
- authCapabilities: phoneSignIn is now phone+PIN (always true, no SMS);
  google/apple are true only when client IDs are configured.

+26 tests (accounts/test_w8_auth.py); full suite 404 green under CI config.
W7 capability tests updated for the redefined phoneSignIn semantics.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tedtadesse
tedtadesse merged commit ece4ef9 into develop Jul 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant