Skip to main content

Multi-Modal Identity & Authentication

Status: PLANNED (V1.0–V1.3) Effort: XL (6-8 weeks, spread across releases) Dependencies: Auth (done), SSO Login (done) Priority: HIGH — Enables families with kids, accessibility


The Story: Sophie Logs In

Sophie is 8 years old. She has no email address, no password, no phone. She walks up to the family tablet and says:

"Morphee, it's me!"

Her voice is recognized. She's in. Her Space opens with her tasks, her conversations, her canvas — exactly where she left off. She creates a task ("finish math homework"), asks Morphee a question, and logs out by walking away.

Her dad Sebastien has email + 2FA. Her grandmother has face recognition because she forgets passwords. Her au-pair has a temporary voice profile that expires in 3 months.

Everyone uses the same Morphee. Everyone authenticates differently. That's multi-modal identity.


Core Principle: Identity =/= Email

Traditional:
User = Email + Password → Access

Morphee:
Identity (one person)
├── Auth Method 1: Voice ("Morphee, it's me")
├── Auth Method 2: Face (smile at camera)
├── Auth Method 3: Email + Password
├── Auth Method 4: GitHub OAuth
├── Auth Method 5: Passkey (YubiKey)
└── Auth Level → ACL decisions

One identity, many ways to prove you're you. ACL actions can require specific methods or combinations:

ActionRequiredWhy
Create a taskAny method (level 1+)Low risk
Change group settings2FA or biometric (level 2+)Medium risk
Delete the groupParent/admin + 2FA (level 3)High risk
Kid invites a friendParent approvalParental control

Architecture

Authentication Levels

LevelMeaningExample
1Single factorEmail/password, OAuth
2Biometric or 2FAFace, voice, TOTP
3Multi-factor + biometricFace + TOTP, voice + hardware key

Step-Up Authentication

When an action requires a higher level than the current session:

Sophie (level 2, voice) tries to delete group
→ ACL: "delete_group requires level 3 + parent approval"
→ Step-up challenge issued
→ Dad gets notification: "Sophie wants to delete the group. Approve?"
→ Dad authenticates (face/2FA) and approves
→ Action completes

This works for any escalation — a developer using email+password who tries to access billing gets a TOTP challenge, not a rejection.

Identity Model

class Identity(BaseModel):
id: str # UUID
display_name: str # "Sophie" — no email required
avatar_url: str | None
date_of_birth: date | None # For age-based ACL
is_minor: bool # Jurisdiction-aware (EU: 16, US: 13)
parent_identity_id: str | None # Link to parent for kids
groups: list[GroupMembership]

class AuthenticationMethod(BaseModel):
id: str
identity_id: str
method_type: Literal[
"email_password", "github_oauth", "google_oauth", "apple_oauth",
"face_recognition", "voice_recognition", "passkey",
"totp_2fa", "sms_2fa", "hardware_key"
]
primary: bool
verified: bool
biometric_template_id: str | None # Vault reference, NEVER raw data
last_used_at: datetime | None

class AuthenticationSession(BaseModel):
session_id: str
identity_id: str
methods_used: list[str] # ["voice_recognition"]
authentication_level: int # 1, 2, or 3
expires_at: datetime

Biometric Processing — Local Only

All biometric processing happens on-device via Tauri Rust. No face or voice data ever leaves the device.

Face recognition: candle (FaceNet/ArcFace) → 512-dim embedding → cosine similarity > 0.85 Voice recognition: candle (ECAPA-TDNN) → speaker embedding → cosine similarity > 0.90 Liveness detection: eye blinks + head movement + texture analysis (face), speech naturalness + environment noise (voice)

Templates are stored in the VaultProvider (OS keychain on desktop, encrypted SQLite on Android). Only a template_id reference is stored in the database.

Connection to the Runtime Hierarchy

Biometric models are excellent candidates for the compilation chain (see ROADMAP.md — Knowledge Pipeline):

ComponentRuntimeRationale
Face encoder (FaceNet)WasmRuntime (Level 3)Fixed model, performance-critical, runs on all platforms
Voice encoder (ECAPA)WasmRuntime (Level 3)Same — compiled, sandboxed, portable
Liveness detectionWasmRuntime (Level 3)Security-critical, must be tamper-resistant
Age estimation from facePythonRuntime (Level 1)Experimental, needs iteration
Custom passphrase logicLLMRuntime (Level 0)Flexible — "say something about your favorite animal"

Biometric WASM modules are not marketplace-shareable (they contain personal templates). But the model architecture could be shared — a community could publish better face encoders as WASM extensions.


Use Cases

1. Kid Without Email (Primary Use Case)

Parent creates Sophie's identity (no email needed):
→ Display name: "Sophie"
→ Date of birth: 2018-05-15
→ is_minor: true, parent_identity_id: <dad_id>

Parent enrolls Sophie's voice:
→ Sophie says "Morphee, it's me" 5 times
→ Voice template stored in vault (encrypted)

Daily use:
→ Sophie: "Morphee, it's me" → authenticated (level 2)
→ Creates tasks, chats, uses canvas → all allowed (level 1+ required)
→ Tries to change settings → parent approval required → dad notified

2. Multi-Method Adult

Dad has: email+password (primary), GitHub OAuth, TOTP 2FA, face recognition

Quick morning login: face recognition → level 2 → full access
Sensitive action (delete group): level 3 required → step-up → enters TOTP → level 3
New device: no face enrolled → email+password → level 1 → adds TOTP → level 2

3. Accessibility: Voice-Only

Maria (visually impaired) uses only voice:
→ "Morphee, it's me" → authenticated
→ All interactions via voice commands
→ Sensitive actions: voice + SMS code ("Morphee, my code is 123456")

4. Temporary Access (Au-pair, Contractor)

Au-pair enrolled with voice, expiry date set (3 months)
→ Full access to family Space during contract
→ Auto-revoked on expiry
→ No residual biometric data (vault cleanup)

Security & Privacy

Biometric Data Rules

  1. NEVER store raw biometric data (images, audio) in the database
  2. ALWAYS store templates in VaultProvider (encrypted at rest)
  3. ALWAYS process biometrics locally (Tauri Rust, never cloud)
  4. GDPR: full biometric deletion on request (templates + auth methods)
  5. Consent: explicit opt-in for each biometric method, revocable anytime
  6. Liveness: required for all biometric auth (prevents photo/recording attacks)

Parent Controls for Minors

  • Parent must authenticate to create/modify a minor's identity
  • Minor's authentication methods can only be managed by parent
  • Age-based ACL policies enforced automatically (jurisdiction-aware)
  • Parent approval requests for sensitive actions (with notification)
  • Parent can see activity log, revoke access instantly

Rollout Plan

V1.0: Multi-Method Login (2 weeks)

  • Identity + AuthenticationMethod models
  • Support email, GitHub/Google/Apple OAuth (leveraging existing SSO)
  • JWT with authentication_level claim
  • Frontend: multi-method login screen
  • Database migration: extend users → identities
  • Tests: multi-method authentication flows

V1.0: Parent-Kid Identity (2 weeks)

  • Create minor identity (no email required)
  • Parent-child identity linking
  • Age-based ACL policies
  • Parent approval request system
  • Kid-friendly UI (larger buttons, simpler language)
  • Tests: parent-kid workflows

V1.3: Biometric Authentication (2 weeks)

  • Tauri Rust: face encoding via candle (FaceNet/ArcFace)
  • Tauri Rust: voice encoding via candle (ECAPA-TDNN)
  • Vault integration for template storage
  • Frontend: FaceRecognitionAuth + VoiceRecognitionAuth components
  • Liveness detection (face + voice)
  • Tests: biometric enrollment + authentication

V1.3: Step-Up Authentication (1 week)

  • Step-up challenge system
  • Authentication requirements per action/resource
  • Frontend: StepUpAuthDialog component
  • ACL integration
  • Tests: step-up flows

Future

  • Passkeys (WebAuthn) — hardware security keys, OS biometric
  • Behavioral biometrics — typing patterns, usage patterns
  • Continuous authentication — re-verify periodically during session
  • Biometric fusion — combine face + voice for higher confidence
  • Age estimation — auto-detect minor status from face (PythonRuntime → WasmRuntime)

Database Schema

-- Identities (extends existing users concept)
CREATE TABLE identities (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
display_name TEXT NOT NULL,
avatar_url TEXT,
date_of_birth DATE,
is_minor BOOLEAN DEFAULT FALSE,
parent_identity_id UUID REFERENCES identities(id) ON DELETE SET NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Authentication methods (multiple per identity)
CREATE TABLE authentication_methods (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
identity_id UUID NOT NULL REFERENCES identities(id) ON DELETE CASCADE,
method_type TEXT NOT NULL,
primary_method BOOLEAN DEFAULT FALSE,
verified BOOLEAN DEFAULT FALSE,
last_used_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
biometric_template_id TEXT, -- Vault reference only
oauth_provider_user_id TEXT,
oauth_email TEXT,
email TEXT,
email_verified BOOLEAN DEFAULT FALSE,
totp_secret_id TEXT, -- Vault reference
expires_at TIMESTAMP WITH TIME ZONE, -- For temporary access
UNIQUE(identity_id, method_type, email)
);

-- Step-up authentication challenges
CREATE TABLE step_up_challenges (
challenge_id UUID PRIMARY KEY,
identity_id UUID NOT NULL REFERENCES identities(id) ON DELETE CASCADE,
required_methods TEXT[] NOT NULL,
reason TEXT NOT NULL,
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
completed BOOLEAN DEFAULT FALSE
);

-- Parent approval requests
CREATE TABLE parent_approval_requests (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
child_identity_id UUID NOT NULL REFERENCES identities(id) ON DELETE CASCADE,
parent_identity_id UUID NOT NULL REFERENCES identities(id) ON DELETE CASCADE,
action TEXT NOT NULL,
resource_type TEXT NOT NULL,
resource_id UUID,
status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'approved', 'denied')),
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
decided_at TIMESTAMP WITH TIME ZONE
);

This is the foundation for truly family-friendly, accessible, secure AI. A platform where a grandmother, a dad, an 8-year-old, and an au-pair can all share the same Morphee — each authenticating in the way that works best for them.