Core Docs

Registration & Login

Registration & Login



Complete flows for user registration, login, third-party auth, and 2FA verification. All flows are single-page, AJAX-driven with progressive screen reveal.

Architecture



Single-Page, Progressive Reveal



All registration and login flows are served as a single HTML page from core.auth.medkronos.com. The page loads all screen components at once, but only the current screen is visible. Transitions between screens are handled by JavaScript — no page reloads, no framework. Just DOM manipulation.

Page load (all screens rendered, only screen 1 visible)


Screen 1 visible ──user action──→ AJAX call to core.auth API
│ │
▼ ▼
Screen 2 visible ←── response ── API validates/creates


...progressive reveal until flow completes


Connection Tokens



When a user is redirected from an app to core.auth for registration/login, the app issues a connection token and passes it as a URL parameter (connection_ref). This token carries the app context through the entire flow:

  • Which app initiated the flow

  • Where to redirect after completion

  • What state/CSRF token the app expects back

-- connection_tokens table
-- See: /02-L2-architecture/02-auth/08-database-schemas


If there's no connection_ref, the user came directly to core.auth.medkronos.com and there's no app to redirect back to.

Frontend Technology



  • HTML/CSS/JS served from core.auth domain

  • Stylesheets from core.assets (core.backend HTML init)

  • No framework — vanilla JS, DOM manipulation

  • AJAX calls to core.auth API endpoints

  • Mobile responsive

Registration Flow



Screen 1 — Info & Entry Point



┌─────────────────────────────────────────┐
│ │
│ Welcome to UNVRSL │
│ │
│ [ Let's Register ] │
│ │
│ ── or continue with ── │
│ │
│ [G] [A] [F] │
│ Google Apple Facebook │
│ │
│ Already have an account? Log in │
│ │
│ [Cancel] │
│ │
└─────────────────────────────────────────┘


  • "Let's Register" → Screen 2 (direct registration)

  • Google/Apple/Facebook → redirect to provider OAuth flow

  • "Log in instead" → switch to Login Flow (Screen 1)

  • "Cancel" → redirect back to app (if connection_ref exists) or close

Third-Party Auth Redirect



User clicks "Continue with Google"


JS redirects to: core.auth.medkronos.com/auth/google?connection_ref=CONN_TOKEN


core.auth redirects to Google OAuth consent screen


User authorizes with Google


Google redirects back to: core.auth.medkronos.com/auth/google/callback


core.auth:
1. Receives OAuth code from Google
2. Exchanges code for Google access token
3. Fetches user profile (name, email, avatar)
4. Checks: does a user_third_party_auths record exist for this provider+provider_user_id?

├── Yes → existing account found → skip to Login completion

└── No → new user:
├── Check: does a user exist with this email?
│ ├── Yes → prompt: "An account with this email exists. Log in to link Google."
│ └── No → create new user account:
│ ├── Generate random password (16 chars, alphanumeric)
│ ├── Hash with Argon2id
│ ├── Set email_verified = true (Google verified it)
│ ├── Store display_name, avatar_url from Google profile
│ ├── Create user_third_party_auths record
│ ├── Send welcome email with generated password
│ └── Continue to Screen 5 (success or app authorization)


Welcome email content:
Subject: Your UNVRSL Account

Hi [Name],

Your account was created via Google Sign-In.

We generated a password for you in case you want to log in
without Google:

Password: [random-16-chars]

⚠️ If you plan to use password login, please:
1. Log in and change this password in account settings
2. Delete this email

If you only use Google Sign-In, you can ignore this.


Screen 2 — Basic Info (Direct Registration)



┌─────────────────────────────────────────┐
│ │
│ Create Your Account │
│ │
│ First name: [ ] │
│ Last name: [ ] │
│ Email: [ ] │
│ Phone: [ ] │
│ Password: [ ] │
│ Confirm: [ ] │
│ │
│ [Continue] │
│ [Back] │
│ │
└─────────────────────────────────────────┘


Password policy:
  • Minimum 10 characters

  • Hashed with Argon2id (PASSWORD_ARGON2ID)

  • No breach database checking

Validation (AJAX):
POST /api/register/validate
{
"email": "user@example.com",
"phone": "+41...",
"password": "..."
}

Response:
{
"valid": true,
"errors": [] // or ["Email already registered", "Password too short"]
}


If the email is already registered, the response includes a suggestion: "An account with this email exists. [Log in instead?]"

Screen 3 — Email + Code Verification



┌─────────────────────────────────────────┐
│ │
│ Verify Your Email │
│ │
│ We sent a code to user@example.com │
│ │
│ Code: [ - - - - ] │
│ │
│ [Verify] │
│ Resend code (55s) │
│ [Back] │
│ │
└─────────────────────────────────────────┘


Flow:
POST /api/register/send-code
{ "email": "user@example.com" }

→ core.auth generates 6-digit code, stores hashed, sends via email
→ Code expires in 10 minutes

POST /api/register/verify-code
{ "email": "user@example.com", "code": "123456" }

→ core.auth verifies code hash
→ On success: mark email_verified = true, proceed to Screen 4
→ On failure: 401, up to 3 attempts before lockout (15 min)


Phone verification (optional, if phone provided):
  • Same flow: send SMS code, verify, mark phone_verified = true

  • Can be done in parallel or sequentially after email

Screen 4 — Biometric Setup (Optional)



┌─────────────────────────────────────────┐
│ │
│ Quick Login Setup │
│ │
│ Use fingerprint or face recognition │
│ for faster login next time. │
│ │
│ [ Set Up Biometric ] │
│ │
│ Skip for now │
│ │
└─────────────────────────────────────────┘


Only shown if the platform supports WebAuthn. Detected via:
if (window.PublicKeyCredential &&
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()) {
// Show biometric screen
}


If the user taps "Set Up Biometric" → triggers WebAuthn registration flow (see 2FA & Passkeys).

If "Skip for now" → proceed to Screen 5.

Screen 5 — Completion



If registered directly (no connection_ref):
┌─────────────────────────────────────────┐
│ │
│ ✓ Account Created! │
│ │
│ Welcome to UNVRSL, [Name]. │
│ │
│ [Go to Dashboard] │
│ │
└─────────────────────────────────────────┘


If registered via app (has connection_ref):
→ Switch to App Authorization Flow (see below).

Login Flow



Screen 1 — Login Entry Point



┌─────────────────────────────────────────┐
│ │
│ Log In to UNVRSL │
│ │
│ Email: [ ] │
│ Password: [ ] │
│ │
│ [ Log In ] │
│ │
│ ── or continue with ── │
│ │
│ [G] [A] [F] │
│ Google Apple Facebook │
│ │
│ [📱 Log in with QR code] │
│ │
│ Don't have an account? Register │
│ │
│ [Cancel] │
│ │
└─────────────────────────────────────────┘


  • Email + password → Screen 2

  • Google/Apple/Facebook → third-party auth redirect (same as registration)

  • QR code → QR Login Flow (see QR Login)

  • "Register instead" → Registration Screen 1

  • "Cancel" → redirect back to app or close

Screen 2 — Credential Verification



POST /api/login
{ "email": "user@example.com", "password": "..." }

Response (success):
{
"status": "ok",
"2fa_required": false
}

Response (2FA needed):
{
"status": "2fa_required",
"challenge_id": "abc-123",
"2fa_type": "totp" // or "webauthn"
}

Response (failure):
{
"status": "error",
"error": "Invalid credentials"
}


Screen 3 — 2FA Verification (If Required)



┌─────────────────────────────────────────┐
│ │
│ Two-Factor Authentication │
│ │
│ Enter the code from your app: │
│ │
│ Code: [ - - - - ] │
│ │
│ [Verify] │
│ Use recovery code instead │
│ │
└─────────────────────────────────────────┘


For TOTP:
POST /api/verify-2fa
{ "challenge_id": "abc-123", "code": "123456" }

→ Verify code against stored secret (±1 window tolerance)
→ On success: issue JWT + session_ref cookie
→ On failure: 401, up to 3 attempts before lockout


For WebAuthn:
POST /api/verify-2fa/webauthn
{ "challenge_id": "abc-123" }

→ Returns PublicKeyCredentialRequestOptions
→ Browser shows biometric prompt
→ User authenticates
→ On success: issue JWT + session_ref cookie


Screen 4 — Biometric Login (If Configured)



If the user has a passkey registered, offer biometric login as the primary option:

┌─────────────────────────────────────────┐
│ │
│ Welcome Back │
│ │
│ [ Use Fingerprint ] │
│ │
│ Use password instead │
│ │
└─────────────────────────────────────────┘


This screen appears before the password prompt if the user has passkeys enabled. It's the path of least resistance for returning users.

Screen 5 — Login Completion



If logged in directly (no connection_ref):
→ User is logged in. Redirect to dashboard or the URL they originally requested.

If logged in via app (has connection_ref):
→ Check if user has authorized this app.
→ If yes: issue auth code, redirect back to app.
→ If no: show App Authorization screen.

Account Already Exists (Social Login)



When a user tries to register via social login and an account with the same email already exists:

User clicks "Continue with Google"


Google returns email: user@example.com


core.auth checks: user exists with this email?

└── Yes → check: already linked to this Google account?

├── Yes → log in directly (skip to completion)
└── No → prompt:
"An account with user@example.com already exists.
Log in with your password to link your Google account."


User enters password → verified


core.auth creates user_third_party_auths record (links Google)


User is logged in, Google is now linked


This prevents duplicate accounts while allowing users to link multiple social providers.

Password Policy



RuleValue






Minimum length10 characters
Hashing algorithmArgon2id (PASSWORD_ARGON2ID)
Breach database checkingNone (for now)
SaltAutomatic (PHP/Argon2id handles this)
Work factorPHP defaults (configurable)

Rate Limiting




EndpointLimitWindowAction





/api/login5 attempts15 minLock account + notify
/api/register/send-code3 codes10 minTemporary block
/api/register/verify-code3 attempts10 minLock verification + require new code
/api/verify-2fa3 attempts5 minLock 2FA + require recovery code

Rate limits are per-IP and per-user.

API Endpoints Summary




EndpointMethodPurpose

















/api/register/validatePOSTValidate registration fields
/api/register/send-codePOSTSend email/phone verification code
/api/register/verify-codePOSTVerify the code
/api/register/completePOSTCreate user account
/api/loginPOSTAuthenticate credentials
/api/verify-2faPOSTVerify TOTP code
/api/verify-2fa/webauthnPOSTInitiate/verify WebAuthn challenge
/auth/googleGETRedirect to Google OAuth
/auth/google/callbackGETHandle Google OAuth callback
/auth/appleGETRedirect to Apple Sign-In
/auth/apple/callbackGETHandle Apple callback
/auth/facebookGETRedirect to Facebook OAuth
/auth/facebook/callbackGETHandle Facebook callback
/auth/qr/generatePOSTGenerate QR login code
/auth/qr/statusGETPoll QR scan status
/auth/qr/confirmPOSTConfirm QR login from scanning device




Next: 2FA & Passkeys — TOTP, WebAuthn, biometric setup details.