Skip to main content
POST
/
api
/
users
/
sync
curl -X POST 'http://localhost:5079/api/users/sync' \
  -H 'Content-Type: application/json' \
  -d '{
    "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "email": "user@example.com",
    "name": "John Doe"
  }'
{
  "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "email": "user@example.com",
  "synced": true
}

Authentication

Not Required (No [Authorize] attribute) Public endpoint for user synchronization

Request Body

id
string
required
User UUIDValidation (Lines 25-28):
if (!Guid.TryParse(request.Id, out Guid userGuid)) {
    return BadRequest("Invalid user ID format");
}
Constraints:
  • MUST be valid GUID format
  • MUST NOT be empty or null
email
string
User email addressValidation: None in controllerNullable: Allowed (passed to service as-is, Line 30)
name
string
User display nameValidation: None in controllerNullable: Yes (Line 51)
phone
string
User phone numberUsage: NOT USED (Line 50)Note: Accepted in request but not passed to service
avatarUrl
string
User avatar image URLUsage: NOT USED (Line 52)Note: Accepted in request but not passed to service
provider
string
Authentication provider nameUsage: NOT USED (Line 53)Note: Accepted in request but not passed to service
curl -X POST 'http://localhost:5079/api/users/sync' \
  -H 'Content-Type: application/json' \
  -d '{
    "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "email": "user@example.com",
    "name": "John Doe"
  }'
{
  "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "email": "user@example.com",
  "synced": true
}

Side Effects

Database Mutations (Line 30):
await _userSyncService.EnsureUserExistsAsync(userGuid, request.Email, request.Name);
Tables Written:
  • users table (UPSERT operation)
UPSERT Logic (service-level):
INSERT INTO users (id, email, name, updated_at)
VALUES ($1, $2, $3, NOW())
ON CONFLICT (id) DO UPDATE
SET email = EXCLUDED.email,
    name = EXCLUDED.name,
    updated_at = NOW()
Fields Synced:
  • id: User UUID (primary key)
  • email: User email (from request)
  • name: User display name (from request)
  • updated_at: Current timestamp
Fields NOT Synced: phone, avatarUrl, provider (not passed to service, Lines 50-53)

Authorization

No Authentication: Endpoint publicly accessible Security Risk: Anyone can sync user data
  • No ownership verification
  • No rate limiting documented
  • Potential for abuse
Intended Use: Called by authentication system after user signup/login

Permissions

Who Can Sync:
  • Anyone (no authentication required)
What Can Be Synced:
  • User ID, email, name only
  • phone, avatarUrl, provider silently ignored

Edge Cases

  1. Invalid GUID: 400 error (Lines 25-28)
  2. Null email: Allowed, passed to service (Line 30)
  3. Null name: Allowed, passed to service (Line 30)
  4. Empty string email: Allowed (no validation)
  5. Empty string name: Allowed (no validation)
  6. User already exists: Updated (UPSERT operation)
  7. User doesn’t exist: Created (UPSERT operation)
  8. Concurrent syncs: Last write wins (no locking documented)

Error Conditions

CodeHTTPCauseController Line
N/A400Invalid GUID format25-28
N/A500Service exception38-42
Exception Handling (Lines 38-42):
catch (Exception ex) {
    // Log error but don't expose details
    return StatusCode(500, new { error = "Failed to sync user" });
}
Error Message: Generic “Failed to sync user”
  • Exception details NOT exposed (unlike other endpoints)
  • Logged internally (Line 40 comment)

Behavioral Guarantees

Idempotency: YES
  • Multiple calls with same data have same effect
  • UPSERT operation ensures idempotency
  • Safe to retry
Atomicity: Single UPSERT query (atomic) Data Overwrite: Always overwrites email and name
  • No merge logic
  • Previous values lost

Validation Rules

Controller-Level Validation:
  • ✅ ID format (GUID)
  • ❌ Email format (not validated)
  • ❌ Name length (not validated)
  • ❌ Required fields (only ID required)
Service-Level Validation: Not enforced by server contract

Response Format

Success Response (Lines 32-36):
  • Echoes id and email from request
  • Adds synced: true field
  • name NOT echoed in response
Failure Response (Line 41):
  • Generic error message
  • No details exposed

Use Cases

Authentication Integration:
  • Called after Supabase Auth signup
  • Called after JWT login
  • Ensures user exists in application database
User Creation:
  • Creates user row before creating threads
  • Required for foreign key constraints
User Updates:
  • Updates email/name if changed in auth system

Security Implications

Public Endpoint:
  • No authentication required
  • Potential for data pollution
  • Could be rate-limited at infrastructure level
Data Exposure:
  • Email addresses can be synced by anyone knowing user ID
Intended Design: Trust authentication system to call this endpoint
  • NOT designed for direct client calls
  • Should be called by backend after auth verification

Unused Fields

Accepted but Ignored (Lines 50-53):
  • phone: Defined in request model, not used
  • avatarUrl: Defined in request model, not used
  • provider: Defined in request model, not used
Reason: Request model may be shared with other services
  • Controller only uses id, email, name
Behavior: Silently ignored, no error