Skip to content

feat(eliza-app): implement phone-first auth with auto-provision#271

Merged
0xbbjoker merged 11 commits intodevfrom
feat/eliza-app-auth-flow-phone-first
Feb 2, 2026
Merged

feat(eliza-app): implement phone-first auth with auto-provision#271
0xbbjoker merged 11 commits intodevfrom
feat/eliza-app-auth-flow-phone-first

Conversation

@0xbbjoker
Copy link
Collaborator

@0xbbjoker 0xbbjoker commented Feb 2, 2026

Summary

Simplifies eliza-app authentication by removing OTP flow in favor of auto-provision:

  • iMessage: Auto-provision users on first message (supports both phone and Apple ID email)
  • Telegram: Require OAuth + phone number input to prevent bot abuse
  • Cross-platform: Same phone number links accounts across Telegram and iMessage

Changes

Backend

  • blooio/route.ts: Auto-provision users by phone OR email (removed rejection of Apple IDs)
  • telegram/route.ts: Keep OAuth enforcement, phone number required
  • user-service.ts: Added findOrCreateByEmail, findOrCreateByTelegramWithPhone, cross-platform linking

Removed

  • OTP service and endpoints (send-otp, verify-otp routes)
  • Related tests (otp-service.test.ts, phone-auth-routes.test.ts)

Added

  • SPEC-eliza-app-auth-flow.md: Comprehensive specification document
  • cleanup-eliza-app-user.ts: Development script for testing
  • oauth-enforcement.test.ts: New tests for auth logic (37 passing)

Test plan

  • Run bun test tests/unit/eliza-app/oauth-enforcement.test.ts - 37 tests pass
  • Test iMessage from phone number → auto-provision works
  • Test iMessage from Apple ID email → auto-provision works
  • Test Telegram DM without signup → shows OAuth redirect
  • Test Telegram OAuth + phone → creates account
  • Test cross-platform: iMessage first → Telegram OAuth links accounts

🤖 Generated with Claude Code


Note

Medium Risk
Medium risk because it changes core authentication/user-linking flows and identity mapping (phone/email/Telegram) used to create sessions and route messages; mistakes could cause account conflicts or mis-association across platforms.

Overview
Eliza App auth is reworked to remove phone OTP login and standardize on Telegram OAuth + phone linking. The /auth/telegram endpoint now requires a phone_number (validated/normalized to E.164) and calls findOrCreateByTelegramWithPhone, returning conflict errors (409) when the phone is already linked or mismatched.

iMessage (Blooio) webhook now auto-provisions by sender identifier (phone or Apple ID email) with new email validation/normalization helpers, and it switches conversation entityId to user.id for unified cross-platform memory. The Telegram webhook stops auto-provisioning and instead enforces prior OAuth registration, responding with a signup link when the user isn’t registered.

OTP API routes/service and their unit tests are deleted, a new unit test suite covers OAuth enforcement/identifier handling, and a cleanup-eliza-app-user.ts script is added to remove test users/orgs and clear session keys.

Written by Cursor Bugbot for commit efa35f4. This will update automatically on new commits. Configure here.

Remove OTP flow in favor of simpler authentication:

- iMessage: Auto-provision users on first message (phone or Apple ID email)
- Telegram: Require OAuth + phone number to prevent bot abuse
- Cross-platform: Same phone links accounts across Telegram/iMessage

Key changes:
- Blooio webhook: Auto-provision by phone OR email (no more rejection)
- Telegram webhook: Keep OAuth enforcement, require phone
- User service: Add findOrCreateByEmail, findOrCreateByTelegramWithPhone
- Remove: OTP service, send-otp/verify-otp endpoints

Tests: 37 passing, no LARP assertions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel
Copy link

vercel bot commented Feb 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
eliza-cloud-v2 Ready Ready Preview, Comment Feb 2, 2026 7:32pm

@coderabbitai
Copy link

coderabbitai bot commented Feb 2, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude

This comment was marked as outdated.

@claude

This comment was marked as outdated.

0xbbjoker and others added 2 commits February 2, 2026 17:37
Addresses PR review feedback about weak email validation.
Creates isValidEmail(), normalizeEmail(), and maskEmailForLogging()
with proper handling for edge cases.

PR: #271

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reject invalid email formats before auto-provisioning.
Use proper email masking for consistent logging.

Addresses PR review: "Missing email format check before creating user"

PR: #271

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
0xbbjoker and others added 4 commits February 2, 2026 17:39
Replace inline regex with maskEmailForLogging() which handles
emails with prefixes shorter than 4 characters gracefully.

Addresses PR review: "Email masking regex fails on short emails"

PR: #271

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
iMessage delivery doesn't prove the user owns the email address
(shared devices, etc.). Set email_verified=false until proper
email verification is implemented.

Addresses PR review: "email_verified: true for Apple ID emails is questionable"

PR: #271

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive tests for isValidEmail(), normalizeEmail(), and
maskEmailForLogging() functions including:
- Invalid formats (@, @@, test@, @test, etc.)
- Missing TLD
- Empty/null inputs
- Short/long inputs
- Short email prefixes

45 tests passing.

Addresses PR review: "Test coverage gaps - missing email validation edge cases"

PR: #271

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes two issues reported by Cursor Bugbot:

1. Missing conflict check in Scenario 1: Before updating phone on
   existing Telegram user, check if phone is already taken by another
   user. Returns proper 409 instead of 500 on unique constraint error.

2. Missing race condition handling in Scenario 3: Wrap user creation
   with try-catch and isUniqueConstraintError recovery, matching the
   pattern used in findOrCreateByPhone and findOrCreateByEmail.

PR: #271 (comment)
PR: #271 (comment)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@0xbbjoker
Copy link
Collaborator Author

Claude says: Fixed both Cursor Bugbot issues in commit 3c86417:

Issue 1 - Missing conflict check (Medium Severity):
Added phone uniqueness check in Scenario 1 before updating phone on existing Telegram user. Now checks if phone is already owned by another user and throws PHONE_ALREADY_LINKED error, which the auth route catches and returns as a proper 409 response instead of 500.

Issue 2 - Missing race condition handling (Low Severity):
Wrapped createUserWithOrganization in Scenario 3 with try-catch and isUniqueConstraintError recovery, matching the pattern used in findOrCreateByPhone and findOrCreateByEmail.

~ Claude Opus 4.5

0xbbjoker added a commit to elizaOS/eliza-app that referenced this pull request Feb 2, 2026
Simplify authentication by removing OTP flow:

- get-started: New flow - Telegram OAuth → Phone input → Success
- connected: Always show iMessage number, keep upstream dropdown UI
- auth-context: Remove OTP methods, update loginWithTelegram signature
- Delete unused TelegramLoginButton component

Backend PR: elizaOS/cloud#271

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@claude

This comment was marked as outdated.

Addresses two new Bugbot issues:

1. Scenario 2 race: Re-check telegram_id before linking Telegram to
   phone user. Prevents two Telegram accounts racing to link to same
   phone user.

2. Scenario 1 phone mismatch: If existing Telegram user already has a
   different phone linked, return PHONE_MISMATCH error instead of
   silently returning mismatched data.

PR: #271 (comment)
PR: #271 (comment)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@0xbbjoker
Copy link
Collaborator Author

Claude says: Fixed both new Bugbot issues in commit bf55f98:

Issue: Race condition in Scenario 2 (cross-platform linking)
Added re-check of telegram_id before linking Telegram to phone user. If another request linked a different Telegram account in the meantime, returns PHONE_ALREADY_LINKED error.

Issue: Scenario 1 returns mismatched phone
Added check: if existing Telegram user already has a different phone linked, returns new PHONE_MISMATCH error instead of silently returning mismatched data.

~ Claude Opus 4.5

@claude

This comment was marked as outdated.

1. Wrap update calls in Scenarios 1 & 2 with try-catch for unique
   constraint violations. Converts 500 errors to proper PHONE_ALREADY_LINKED
   responses, matching Scenario 3's pattern.

2. Remove SPEC-eliza-app-auth-flow.md from PR (internal doc).

PR: #271 (comment)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@0xbbjoker
Copy link
Collaborator Author

Claude says: Fixed in commit d9fb254.

Wrapped usersRepository.update calls in Scenarios 1 and 2 with try-catch for unique constraint violations. Now all three scenarios handle race conditions consistently - database errors are caught and converted to proper PHONE_ALREADY_LINKED responses instead of 500 errors.

Also removed the spec doc from the PR as requested.

~ Claude Opus 4.5

@claude

This comment was marked as outdated.

@0xbbjoker
Copy link
Collaborator Author

Thanks for the thorough review!

Re: Critical Issues

  1. TOCTOU Race Condition (pre-flight checks) - Good catch. Will remove the redundant pre-flight checks in the route handler since the service layer already handles this properly with database constraints and try-catch blocks.

  2. Auto-Provision by Unverified Email - Acknowledged. The email_verified: false flag is intentional for this reason. Email verification flow can be added in a follow-up PR if needed.

Re: Medium Priority Issues

  1. Weak Email Validation - Will update linkEmailToUser to use isValidEmail() utility for consistency.

  2. Per-User Rate Limiting - This is actually handled at the application layer: each user starts with $1 in credits, and once depleted, they cannot perform actions that consume credits. This serves as a natural per-user rate limit. Additionally, the ASSISTANT mode actions have credit costs, so spam is self-limiting. Global rate limits remain as secondary protection against abuse before account creation.

  3. Error Handling - Will add a catch-all error handler to prevent 500s from unhandled error types.

Will implement fixes 1, 3, and 5 after the next review iteration.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

…dling

- Remove redundant pre-flight checks in telegram auth route (service layer handles conflicts)
- Add catch-all error handler to prevent uncontrolled 500s
- Use isValidEmail() consistently in linkEmailToUser
- Fix incomplete race condition recovery in Scenario 3 (check phone constraint too)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@0xbbjoker 0xbbjoker merged commit 2fc5731 into dev Feb 2, 2026
4 of 5 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