Skip to main content
The authentication service wraps Auth0 so the mobile and web clients never talk to Auth0 directly. All routes live under /api/v1/auth unless otherwise noted.
Testing locally? Run npx serve -l 3000 from the project root and open http://localhost:3000/test-google-token.html to generate a real Google ID token for testing. See the Google OAuth docs for details.
FlowEndpoint(s)Description
Email/passwordPOST /signup, POST /signinCreate or authenticate users with the native database connection
Google OAuthPOST /google, POST /login/google, GET /login/google, GET /callback/googleExchange Google ID tokens or run the redirect-based flow
TokensPOST /refresh, POST /signoutRotate or revoke Auth0 tokens
ProfileGET /me, PATCH /meFull profile overview with usage stats, update profile with avatar upload
Phone OTPPOST /send-otp, POST /resend-otp, POST /verify-otpExotel-backed OTP login
WebhooksPOST /webhooks/post-registration, POST /post-loginAuth0 server-to-server sync
HealthGET /healthService heartbeat

Prerequisites

  • Auth0 tenant with the database connection enabled and client credentials set in .env (AUTH0_DOMAIN, AUTH0_CLIENT_ID, etc.).
  • Front-channel URLs registered in Auth0 for GET /login/google and GET /callback/google.
  • Exotel credentials for OTP routes and a verified sender ID.
  • Bearer token (Auth0 access token) when hitting any protected route such as /api/v1/auth/me. Use POST /signin or /google to obtain one.

Email + password

curl -X POST https://api.handauncle.com/api/v1/auth/signup \
  -H "Content-Type: application/json" \
  -d '{
    "email": "investor@example.com",
    "password": "GrowWealth123",
    "name": "Puneet"
  }'
Requirements:
  • Password must be ≥8 chars and include uppercase, lowercase, and a digit
    (signupRequestSchema in src/services/auth/types/auth-schemas.ts).
  • Successful signup/signin returns { accessToken, idToken, refreshToken, expiresIn, user }.
POST /signin takes the same body (email + password) and returns the same envelope. Tokens are Auth0-issued JWTs referenced throughout the API.

Google OAuth

1. Token exchange (mobile/native)

curl -X POST https://api.handauncle.com/api/v1/auth/google \
  -H "Content-Type: application/json" \
  -d '{ "idToken": "<google-id-token>" }'
Mobile clients obtain the Google ID token via the platform SDK and exchange it server-side. Try it via the POST /api/v1/auth/google panel.

2. Redirect flow (web)

  1. GET /api/v1/auth/login/google → redirects to Auth0’s hosted login page (optional state query param supported).
  2. GET /api/v1/auth/callback/google → handles the authorization code, fetches user info, syncs MongoDB via userSyncService, and forwards the tokens plus the original state back to the frontend.
Both flows call authOrchestrationService.googleAuth() and return the standard token envelope.

Token lifecycle

Refresh

POST /api/v1/auth/refresh with body { "refreshToken": "<token>" } returns { accessToken, idToken, expiresIn }. No Bearer token required—the refresh token is validated via Auth0 (tokenService.refreshAccessToken).
Use the Refresh Access Token playground to verify your refresh tokens are wired correctly.

Signout

POST /api/v1/auth/signout accepts an optional refreshToken. When provided, the backend revokes it via Auth0; when omitted, the call simply returns { success: true, message: "Successfully signed out" } so clients can clear local state.

Profile (GET & PATCH /me)

The /me endpoint is the unified profile endpoint that replaces the old /profile route.

Get Profile

GET /api/v1/auth/me requires Authorization: Bearer <Access Token>. Returns the full profile overview including user data, usage statistics, and profile context:
{
  "success": true,
  "data": {
    "user": {
      "id": "683b7e9f465b1b4e6753627a4f",
      "email": "investor@example.com",
      "fullName": "Puneet",
      "avatarUrl": "https://cdn.auth0.com/...",
      "preferences": { "language": "en", "theme": "dark" }
    },
    "usage": {
      "conversations": { "total": 42, "active": 38, "archived": 3, "deleted": 1, "lastActiveAt": "..." },
      "shares": { "total": 5, "active": 4, "expired": 0, "revoked": 1, "totalViews": 127, "lastSharedAt": "..." }
    },
    "profileContext": {
      "static": ["..."],
      "recent": ["..."],
      "frequent": ["..."]
    }
  }
}
If the user does not exist locally, the controller auto-creates it based on the Auth0 payload before responding.

Update Profile

PATCH /api/v1/auth/me accepts partial updates for fullName or preferences (language, theme, notifications), and supports avatar upload via multipart form data. Returns the updated profile overview. JSON Request (no avatar):
curl -X PATCH https://api.handauncle.com/api/v1/auth/me \
  -H "Authorization: Bearer <access-token>" \
  -H "Content-Type: application/json" \
  -d '{ "fullName": "Puneet Sharma", "preferences": { "theme": "dark" } }'
Multipart Request (with avatar):
curl -X PATCH https://api.handauncle.com/api/v1/auth/me \
  -H "Authorization: Bearer <access-token>" \
  -F "avatar=@/path/to/photo.jpg" \
  -F 'data={"fullName": "Puneet Sharma"}'
Delete Avatar:
curl -X PATCH https://api.handauncle.com/api/v1/auth/me \
  -H "Authorization: Bearer <access-token>" \
  -H "Content-Type: application/json" \
  -d '{ "_clearAvatar": true }'
Supports JPEG, PNG, GIF, and WebP images. Large images are automatically compressed.

Phone OTP (Exotel)

Phone OTP authentication via Exotel SMS. All routes are under /api/v1/auth.

Required Headers

HeaderRequiredDescription
x-device-idYesStable, unique per device/installation
x-platformNoios, android, or web

Send OTP

curl -X POST https://api.handauncle.com/api/v1/auth/send-otp \
  -H "Content-Type: application/json" \
  -H "x-device-id: device-uuid-123" \
  -H "x-platform: android" \
  -d '{ "phone": "+919876543210" }'
Kicks off an Exotel SMS and enforces cooldowns via otpOrchestrationService.sendOTP.

Resend OTP

curl -X POST https://api.handauncle.com/api/v1/auth/resend-otp \
  -H "Content-Type: application/json" \
  -H "x-device-id: device-uuid-123" \
  -d '{ "phone": "+919876543210" }'
Respects OTP_RESEND_COOLDOWN_SECONDS (default 60s) before dispatching another SMS.

Verify OTP

curl -X POST https://api.handauncle.com/api/v1/auth/verify-otp \
  -H "Content-Type: application/json" \
  -H "x-device-id: device-uuid-123" \
  -d '{
    "phone": "+919876543210",
    "otp": "123456"
  }'
On success, returns the standard auth envelope with Auth0 tokens:
{
  "success": true,
  "data": {
    "accessToken": "eyJhbGciOiJSUzI1NiIs...",
    "idToken": "eyJhbGciOiJSUzI1NiIs...",
    "refreshToken": "v1.MjAyNS0xMi0wMg...",
    "expiresIn": 86400,
    "user": {
      "id": "auth0|692e9f465b1b4e6753627a4f",
      "phone": "+919876543210",
      "name": "HU Phone 3210",
      "phoneVerified": true,
      "email": "919876543210@sms.handauncle.app"
    }
  }
}
The accessToken can be used with all authenticated endpoints just like email/password tokens.

Webhooks (server-to-server)

EndpointAuthPurpose
POST /api/v1/auth/webhooks/post-registrationAuth0 JWT + optional X-Webhook-SecretPrimary hook triggered by Auth0 Actions after signup to create the MongoDB user
POST /api/v1/auth/post-loginAuth0 JWTLegacy hook for syncing profile updates after login
Both routes use auth0JwtMiddleware and are not intended for client apps.

Health

GET /api/v1/auth/health returns the provider info and the exported endpoints, useful for monitoring or smoke tests.

Error format

All controllers extend BaseController and emit the shared error envelope:
{
  "success": false,
  "error": {
    "message": "Validation error",
    "code": "ValidationError"
  },
  "meta": {
    "timestamp": "...",
    "requestId": "..."
  }
}