Koovira Dev Docs
30-core/auth.md

Authentication & Account Lifecycle

Status: 🟢 Production verified · Last validated: 2026-09-06

Signup, login, OTP, password, device management, 2FA, biometric, logout — validated against classs/auth_classes/AuthHandler.php, classs/AuthModule.php, forms/doaction_auth.php, and the live kv_auth_* / customer_master schema.


Architecture (two layers)

  1. AuthHandler (classs/auth_classes/AuthHandler.php, ~2,900 lines) — the real engine.

Holds every method: handleSignup :95, handleVerifyOTP :163, handleResendOTP :214, handleLogin :254, handleForgotPassword :403, handleDeviceResetRequest/Verify :435/:444, handleTwoFactorSend/Verify :453/:470, handleResetPassword :488, handleChangePassword :513, handleCompleteProfile :129, handleOnboardingSave :1110, handleToggleSubProfile :618, handleBiometricLogin :2203, handleLogout :2262, handleLogoutDevice :2316, handleLogoutAll :2341, plus session/history getters (getActiveSessions :2391, getLoginHistory :2404, getPasswordHistory :2417).

  1. AuthModule extends AuthHandler (classs/AuthModule.php) — a thin wrapper that calls

parent::handleX() then adds two cross-cutting concerns:

  • DPDP audit logging — every auth event is logged via `kvDpdpLogAuthEvent(eventType,

userId, meta, riskScore)` with an explicit per-event risk score (e.g. login success 28, login failed 68, OTP verify success 18).

  • Auto-follow seeds — on login success, FriendsModule::applyAutoFollowSeeds($userId)

connects the user with the superadmin (AuthModule.php:60-70).

Dispatch: the front-end POSTs to forms/doaction_auth.php with TYPEACTION (aliases: typeAction/typeaction/action, GET or POST). It instantiates AuthModule and routes by action.

Response contract (every handler returns this shape): activi_status (1 = success), return_messagealert (user message), redirect_url, activity_return_type. The logged-in user id is $_SESSION['auth_customer_id'].


Entry points (validated pages)

PurposePage(s)
Signupsignup.php, register.php
Loginlogin.php
OTPotpverification.php
Onboarding (post-OTP)onboarding.php?signup=1
Forgot / reset passwordforgot-password.php, forgotpassword.php, reset-password.php, reset-password_new.php
Change passwordchangepassword.php, password_history.php
Social signup/logingoogle_signup.php, google_signup_complete.php, google_oauth_signup.php, api/google_oauth_init.php
Logoutlogout.php
Module-specific verify/OTPkyc_otp.php, claim_otp.php, dating_verify.php, propertyadd_otp.php, careerlab_verify.php

Dispatcher actions (doaction_auth.php): SIGNUP, VERIFY_OTP, RESEND_OTP, LOGIN, COMPLETE_PROFILE, PROFILE_QUICK_UPDATE, BIOMETRIC_LOGIN, FORGOT_PASSWORD, RESET_PASSWORD, CHANGE_PASSWORD, AUTH_DEVICE_RESET_REQUEST, AUTH_DEVICE_RESET_VERIFY, AUTH_DEVICE_PICK_LOGOUT, TWOFA_SEND, TWOFA_VERIFY, plus notification actions (GET_NOTIFICATIONS, MARK_NOTIFICATION_READ, MARK_ALL_NOTIFICATIONS_READ).


Data model (validated)

customer_master (119 rows, 2026-09-06 — corrected same-day recount, was 110; this is an

actively-written dev DB) — the identity table One row per profile, not per person. Key columns:

  • rowId (PK), customer_uid, parent_user_id (0/self = top-level person; >0 = a sub-profile's

parent), profile_type enum(social,professional,dating), user_type, company_id.

  • Credentials: email, mobile, password_hash. Verification: is_email_verified,

is_mobile_verified, email_verified_at, mobile_verified_at.

  • KYC: kyc_status, kyc_doc_type, kyc_otp, kyc_otp_timestamp.
  • Account: account_status, account_status_message, activestatus, age_verified,

preferred_language.

Column drift to know (validated): customer_master carries legacy duplicates — password (text) alongside password_hash; customer_email/emailid alongside email; customer_mobile alongside mobile; profile_type_old, parent_user_id_old. Write/read password_hash, email, mobile — treat the old/customer/emailid columns as legacy unless a specific code path proves otherwise.

The kv_auth_* family (the auth store)

TableRowsRole
kv_auth_sessions64active/revoked sessions — polymorphic actor
kv_auth_login_attempts53login attempt log (rate-limit / lockout source)
kv_auth_login_challenges49in-flight OTP/login challenges
kv_auth_trusted_devices12remembered devices (device policy)
kv_auth_password_resets5password reset requests
password_reset_tokens6reset tokens
device_reset_tokens0device-reset tokens
notification_otp_codes25issued OTP codes
otp_attempts_log / otp_verifications0 / 0(dormant — OTP flows use notification_otp_codes + kv_auth_login_challenges)
auth_session_log128 (recounted; was 121)session audit
login_activity_log248 (recounted; was 238)login history (getLoginHistory)
oauth_clients0OIDC clients (see Developer Platform / SSO)
referral_codes / user_referrals13 / 0referral attribution (see below)

kv_auth_sessions columns (validated): session_uid (char36), actor_type + actor_id (polymorphic — a session belongs to a customer, merchant, partner, or padmin), partner_id, actor_role, php_session_id, device_uid, device_fingerprint_hash, ip_address, user_agent, geo_json, risk_score, status, created_at, last_seen_at, logged_out_at, revoked_at, revoked_by_padmin_id, revoke_reason, meta_json. Session lifecycle is managed by classs/KvSessionDevicePolicy.php, KvSessionGuard.php, KvSessionHeartbeat.php (multi-device limits, eviction, heartbeat/last-seen).


Flows

Signup → OTP → onboarding

signup.php  ──POST TYPEACTION=SIGNUP──▶ doaction_auth.php ▶ AuthModule::handleSignup (AuthHandler:95)
  accept_policies=1 required · creates customer_master row (unverified) · issues OTP
  ▶ notification_otp_codes (code) · challenge in kv_auth_login_challenges
  â–¶ DPDP log 'auth_signup*'
otpverification.php ─POST VERIFY_OTP─▶ handleVerifyOTP (AuthHandler:163)
  on success: is_mobile_verified/is_email_verified set · redirect_url='onboarding.php?signup=1'
  â–¶ DPDP log 'auth_verify_otp_success' (risk 18)
onboarding.php ─POST─▶ handleOnboardingSave (:1110)  (profile completion, defaults)

Login

login.php ─POST LOGIN (accept_policies=1)─▶ AuthModule::handleLogin
  â–¶ parent AuthHandler::handleLogin (:254): verify password_hash, rate-limit via kv_auth_login_attempts,
    create kv_auth_sessions row (device fingerprint, risk_score), apply device policy (evict per limits)
  on success: FriendsModule::applyAutoFollowSeeds(); DPDP 'auth_login_success' (risk 28)
  on failure: DPDP 'auth_login_failed' (risk 68)

Multi-device policy (validated in memory + KvSessionDevicePolicy): koovira.com native allows 5 devices; each Koovira-OAuth partner app = 1 active session (2nd login evicts that app's session).

Forgot / reset / change password

FORGOT_PASSWORD → handleForgotPassword (:403) issues a reset (→ kv_auth_password_resets / password_reset_tokens, OTP/token) → RESET_PASSWORD → handleResetPassword (:488) → CHANGE_PASSWORD → handleChangePassword (:513, keeps password_history).

Device reset / 2FA / biometric

AUTH_DEVICE_RESET_REQUEST/VERIFY (:435/:444, device_reset_tokens), TWOFA_SEND/VERIFY (:453/:470), BIOMETRIC_LOGIN (:2203).

Logout

handleLogout (:2262) ends the current session; handleLogoutDevice (:2316) one device; handleLogoutAll (:2341) revokes all — all update kv_auth_sessions.status/logged_out_at.

Sub-profile toggle (identity)

handleToggleSubProfile (:618) activates/deactivates a professional/dating sub-profile row (the canonical TOGGLE_SUB_PROFILE path — do not build a new endpoint). Writes customer_master, professional_profile, dating_profiles.

Social login

Google via google_oauth_signup.php / api/google_oauth_init.php / google_signup_complete.php. OIDC provider side (Koovira as IdP for partner apps) uses oauth_clients + api/v1/auth/* — see the Developer Platform / SSO docs.

Referral attribution

Signup can carry a referral code → referral_codes (13) / user_referrals / referral_tracking; rewards ledger referral_reward_ledger (referral rewards were switched to wallet credit — see ../40-financial/ and memory referral-rewards-wallet-switch).


Business rules (validated)

  • BR-AUTH-001 — signup and login require accept_policies=1 (doaction_auth.php:84,286).
  • BR-AUTH-002 — every auth event is DPDP-logged with a risk score (AuthModule::kvDpdpLogAuthEvent).
  • BR-AUTH-003 — a session is polymorphic (actor_type+actor_id); never assume "user" — a

session may be a merchant/partner/padmin actor.

  • BR-AUTH-004 — multi-device limits are enforced by KvSessionDevicePolicy; exceeding evicts the

oldest per bucket (5 for native Koovira; 1 per OAuth partner app).

Errors (prefix AUTH-E)

IDTriggerDetectionResolution
AUTH-E001wrong passwordhandleLogin returns activi_status!=1; row in kv_auth_login_attemptsuser retries / reset
AUTH-E002OTP invalid/expiredhandleVerifyOTP fail; check notification_otp_codes timestamp + kv_auth_login_challengesRESEND_OTP
AUTH-E003account locked (too many attempts)kv_auth_login_attempts count; account_statuswait / device reset
AUTH-E004device limit reachedsession evicted; kv_auth_sessions statusexpected; AUTH_DEVICE_PICK_LOGOUT
AUTH-E005signup without policy acceptdoaction_auth.php:84UI must send accept_policies=1
AUTH-E006"signup not working" = OTP shown as on-screen image vs emailedenv flag (see memory signup-otp-captcha-bypass)set flag 0 after confirming email delivery

Change-impact

Touches: sessions (device policy), the DPDP audit ledger, auto-follow (social graph), sub-profiles, referral rewards (wallet). Re-test: login/OTP happy path, device eviction, DPDP rows written, password_hash (not legacy password) is the column read/written.