Marmara University crest
Marmara Üniversitesi · Mühendislik Fakültesi
Department of Computer Engineering
Faculty of Engineering crest
Production-deployed multi-tenant biometric identity SaaS · one hosted login button
<FIVUCSAS/>

Face & Identity Verification using Cloud-based SaaS Models

Team · Department of Computer Engineering
Ahmet Abdullah Gültekin ahmetabdullahgultekin@gmail.com github.com/ahmetabdullahgultekin
Ayşe Gülsüm Eren aysegulsumeren@gmail.com
Ayşenur Arıcı aysenurarici@hotmail.com github.com/Aysenur15
Supervisor Assoc. Prof. Dr. Mustafa Ağaoğlu
CSE4298
Engineering Project
Spring 2025 – 2026
01

Introduction

Problem · What we built · Main Goal · Objectives

1. The Problem

  • Password & SMS-OTP login is routinely compromised by phishing, credential stuffing and SIM-swap fraud.
  • Face authentication is vulnerable to presentation attacks — printed photos, video replays, silicone masks, AR filters, deepfake injection.
  • Every new application re-implements auth; KVKK & GDPR compliance is patched on as an afterthought.
  • Mainstream IAM suites (Okta, Auth0, Entra) treat biometrics as a device-local feature and rarely unify digital access, document verification and proctoring under one tenant boundary.
  • Per-frame liveness fails for proctoring — an attacker holds a spoof for 30 s, flashes a real face for one frame, resumes the spoof, and the average passes.

2. What FIVUCSAS Is

FIVUCSASFace & Identity Verification using Cloud-based SaaS Models — is a production-deployed, multi-tenant biometric identity SaaS exposed through one hosted OAuth 2.0 + OIDC + PKCE (RFC 7636) redirect. What we built:

  • Face recognition core — DeepFace 0.0.98 detection → MediaPipe FaceLandmarker 468-point → Facenet-512 embedding (Fernet AES-128 encrypted) → cosine match on pgvector (HNSW m=16/ef=64).
  • The Biometric Puzzle — randomised challenge–response: 7 face actions + 9 hand-gesture actions, EAR / MAR / yaw thresholds, server-nonced UUID, 5-minute TTL.
  • Hybrid liveness — active Puzzle + passive spoof-detector (19 analyzers, MiniFASNet ONNX, 15-axis LivenessProver, session-level peak-sensitive verdict).
  • NFC document subsystem — Turkish T.C. ID + ICAO 9303 passport (BAC, DG1 MRZ, DG2 JPEG2000 face), ML Kit OCR fallback, DG2 face ↔ live selfie cross-check.
  • Ten composable authentication factors — Password, Email OTP, SMS OTP, TOTP, QR Code, Face, Voice, Fingerprint, Hardware Key (FIDO2/WebAuthn), NFC Document.
  • Multi-tenant SaaS — Postgres Row-Level Security on 9 tables (V25), audit-log partitioning (V40 + pg_partman V57); Marmara Üniversitesi live tenant at demo.fivucsas.com.
Main Goal
Deliver a production-grade, KVKK / GDPR-compliant biometric authentication SaaS that any client application can adopt with one OAuth 2.0 / OIDC redirect — replacing fragmented, spoofable, per-app authentication with a single tenant-configurable identity layer that runs on commodity CPU.
Objectives
Objective 01
Face Recognition Core
Sub-second 1:1 / 1:N matching on commodity CPU, no GPU.

Facenet-512 · pgvector HNSW
Objective 02
Active Liveness
Randomised Puzzle defeating photo, replay, deepfake, AR-filter.

MediaPipe · 468 lmk · EAR / MAR
Objective 03
Multi-Tenant SaaS
Ten composable MFA factors shipped by tenant JSON, not Java.

OAuth2 · OIDC · PKCE · RLS
Objective 04
Hybrid Anti-Spoofing
Session-level peak-sensitive verdict + 19-analyzer fusion.

MiniFASNet · ISO 30107-3 L1
02

The Drop-in Identity Button

e-Devlet & reCAPTCHA mental model · side-by-side · 3 use-cases

We position the product through two familiar mental models. "Sign in with e-Devlet" is Türkiye's public-sector SSO gateway; FIVUCSAS offers the same drop-in experience for the private sector. reCAPTCHA adds bot protection to any site with a single HTML snippet; FIVUCSAS adds ten-factor biometric identity verification with a single <FIVUCSAS/> button. For end users: no separate registration on every app. For developers: no login / register pages to write — an OIDC discovery URL and one button.

Three buttons, one mental model

T.C.
e-Devlet ile Giriş Yapturkiye.gov.tr · public sector SSO
I'm not a robot — reCAPTCHAgoogle.com · bot protection drop-in
</>
Sign in with FIVUCSASverify.fivucsas.com · biometric SaaS drop-in
<a class="fivucsas-btn"
   href="https://verify.fivucsas.com/oauth2/authorize
        ?client_id=YOUR_CLIENT_ID
        &response_type=code
        &scope=openid+profile+email
        &redirect_uri=https://yourapp.com/cb
        &code_challenge=...
        &code_challenge_method=S256">
  <FIVUCSAS/> ile Giriş Yap
</a>

Side-by-side comparison

Aspecte-DevletreCAPTCHAFIVUCSAS
Primary purposeSSOBot defenceIdentity verification
ScopePublic-sectorAny webAny web / mobile / desktop
Auth modelGovernment SSOToken-onlyOAuth2 + OIDC + PKCE
BiometricActive Puzzle + Passive PAD + Facenet-512
NFC documentT.C. + ICAO 9303 (mobile) + Web NFC (simple cards)
MFA factors2010 composable
ProctoringWebSocket · session-level verdict
Multi-tenantper-keyPostgres RLS · 9 tables (V25)
IntegrationGov approvalPublic site-keyPublic OIDC + drop-in button
Self-hostDocker Compose · GPU-less
Open sourceMIT (spoof-detector) · OSS roadmap
LegalKVKKGoogle ToSKVKK + GDPR + ISO 30107-3 L1
Bank-grade KYC
Fintech mobile onboarding: face + NFC document + liveness → one session, sub-second verification.
Online exam proctoring
Marmara BYS live at demo.fivucsas.com: continuous identity tracking, 15-axis liveness, incident detection.
KVKK / GDPR onboarding
Local SaaS deployments: EU/TR hosting, Fernet AES-128 embedding encryption, soft-delete + RLS.
03

System Architecture

Hexagonal / DDD · 7 containers · Hetzner CX43
A.

From client to chip — five tiers

Client
Web
React 18 · Vite · Material UI
Mobile / Desktop
Kotlin Multiplatform · Compose
Drop-in widget
@fivucsas/auth-js SDK · OIDC redirect
Gateway
API Gateway · Traefik v3.6
TLS termination · JWT · rate-limit · dynamic routing · admin-IP gating
Services
Identity Core API
Spring Boot 3.4 · Java 21 · Hexagonal port/adapter · OAuth2 issuer
Biometric Processor
FastAPI · Python 3.12 · DeepFace · MediaPipe Tasks · Facenet-512
Storage
PostgreSQL 17 · pgvector
HNSW (bio-proc m=16/ef=64) + IVFFlat (identity lists=100) · RLS · 60 Flyway migrations
Redis 7.4
cache · OTP / puzzle nonces · sessions · pub-sub
Infra
Hetzner CX43
8 vCPU · 16 GB · 150 GB · Ubuntu 24.04 · no GPU
Docker Compose
7 services · Prometheus + Grafana + Loki + Promtail
04

Face Recognition Pipeline — 8 Stages

Detection → Quality → Landmark → Align → Embed → Encrypt → Index → Match

Server-authoritative pipeline in biometric-processor/ (FastAPI, Python 3.12). Every stage is replaceable — backbone, detector and similarity all swap via DI in app/infrastructure/ml/factories/. Verification (1:1) compares against the enrolled vector with cosine distance; identification (1:N) returns pgvector ANN top-k. Aged embeddings (> 2 years) use a more permissive threshold.

01 · Detection
DeepFace 0.0.98
Configurable backend (opencv, ssd, mtcnn, retinaface, mediapipe, yolov8/11/12). DeepFace anti-spoof θ = 0.5.
backend = opencv
app/core/config.py:91-94, 126-136
02 · Quality Gating
Multi-signal scorer
Laplacian blur ≥ 100, min face 80 px, quality ≥ 70, brightness 30–90, occlusion CIE-Lab ΔE (eye 0.6, mouth 0.4).
quality ≥ 70.0
app/core/config.py:158, 291, 292 · occlusion_detector.py
03 · Landmarking
MediaPipe FaceLandmarker
Tasks API (NOT legacy face_mesh). 468-point canonical topology + 478 iris. Eye / nose / mouth / brow / face-oval regions defined.
468 + 10 iris
.../landmarks/mediapipe_landmarks.py:26-45
04 · Alignment
DeepFace align=True
Eye-line affine warp inside DeepFace. Crop scaled to model native input.
align = True
.../detectors/deepface_detector.py:28, 43
05 · Embedding
Facenet-512
512-D L2-normalised. Server-authoritative; client never sees plaintext vector.
dim = 512
.../extractors/deepface_extractor.py:72-75, 132
06 · Encryption
Fernet AES-128 + HMAC
URL-safe Base64 keying. Embeddings sealed at rest. Migration 20260502_0005 ciphertext column.
AES-128-CBC + HMAC-SHA256
.../security/embedding_cipher.py:14, 39
07 · Indexing
pgvector
Biometric-processor: HNSW (m = 16, ef_construction = 64). Identity-core (auth): IVFFlat (lists = 100). Per-tenant uniqueness with deleted_at filter.
HNSW m=16 · ef=64
scripts/add_hnsw_indexes.sql:19-22 · V4.sql:8
08 · Matching
Cosine distance
Default θ = 0.45. Aged-embedding (> 2 yr) θ_aged = 0.38 (more permissive). 1:N top-k pgvector ANN.
θ = 0.45 · θ_aged = 0.38
app/core/config.py:156, 171-180

Honest gap. No in-house EER / FAR / FRR has been measured in the project test fixtures — published rates apply to the underlying Facenet-512 model only. Load-test targets (Login p95 < 300 ms, Verification p95 < 500 ms — load-tests/README.md:137-180) are targets, not measurements. Future work: in-house Marmara cohort EER curve.

05

NFC Document Subsystem — Two Rails

Native mobile (ICAO 9303) · Web NFC (simple cards) · cross-check to live selfie

One logical contract, two physical rails. Rail A — Native mobile NFC: Turkish T.C. ID, Turkish passports and every ICAO 9303 document sharing the same BAC chip are read over Android IsoDep + Bouncy Castle (iOS CoreNFC on roadmap). Rail B — Web NFC: ISO/IEC 14443 Type-A & Type-B simple cards (loyalty cards, membership cards, transit cards, MIFARE Classic / Ultralight, NTAG2xx tags) are read directly from Chrome on Android via the Web NFC API — no native NFC layer required. Both rails speak to the same server-side verifier.

T.C. Yeni Kimlik Kartı
The contactless ISO/IEC 14443 chip lives on the back of the T.C. ID card; on passports it is in the cover. Common ICAO AID A0 00 00 02 47 10 01. The same BAC key derivation (SHA-1 from MRZ) is reused for TD3 passports and every other ICAO 9303 document carrying the same chip.
Standard: ICAO Doc 9303 (Machine Readable Travel Documents)
Spec ref: practice-and-test/PASSPORT_NFC_ROADMAP.md:8

A. Protocols implemented

  • BAC (Basic Access Control) — SHA-1 key derivation from MRZ, identical for Turkish T.C. ID and TD3 passports. PASSPORT_NFC_ROADMAP.md:670-690
  • PACE (Password Authenticated Connection Establishment) — optional for newer passports, scoped not implemented. :164-170
  • Active Authentication · Chip Authentication[future work]
  • EF.SOD validator — 60% complete; CSCA full chain pending. :383-395
  • ICAO check-digit validation: biometric-processor/tests/unit/test_nfc_mrz_route.py:47-88

B. Data Groups parsed

  • DG1 — MRZ: .../TurkishEidNfcReader/.../util/Dg1Parser.kt
  • DG2 — Facial image (JPEG2000 / JP2): Dg2Parser.kt:1-50
  • EF.COM — data-group presence list
  • DG3 / DG4 / DG11 / DG13 / DG14 / DG15: not implemented (roadmap §5.1)

C. Platform & plugin

  • Android native NFC via android.nfc + IsoDep — no third-party NFC plugin needed.
  • Bouncy Castle for BAC crypto. build.gradle:91-96
  • iOS CoreNFC — Kotlin Multiplatform expect / actual stub pending; Android live first.

D. MRZ OCR fallback

  • Google ML Kit Text Recognition 16.0.0 (on-device, offline). build.gradle:78
  • CameraX 1.3.4 for capture pipeline. :70-75
  • Check-digit validates the OCR result before chip contact — no failed BAC attempts.
  • No cloud OCR dependency.

E. Cross-check to live selfie

  • DG2 → decode JPEG2000 → DeepFace detect + align → Facenet-512 embedding.
  • Cosine distance vs the live selfie embedding (same pipeline → fair comparison).
  • Threshold default θ = 0.45; aged θ = 0.38. app/api/routes/verification_pipeline.py

F. Operational notes

  • Timeout 30 s (inherited Turkish eID baseline). PASSPORT_NFC_ROADMAP.md:31
  • Failure modes covered by unit tests: timeout, corrupted payload, invalid checksum, SOD fail. test_nfc_mrz_route.py:95-100
  • Mean chip-read latency — not yet measured in production telemetry.

Rail B — Web NFC (simple cards, no native layer)

G. Cards covered without native NFC

  • MIFARE Classic / Ultralight — store loyalty, library and canteen cards.
  • NTAG2xx tags — promotional tags, product identifiers, NFC stickers.
  • ISO 14443 Type-A & Type-B — city / transit cards (BKT-class read-only profile).
  • Tickets / lanyards / event passes — proximity-pair cards.
  • UID / NDEF-only cards — no BAC cryptography required.

H. Platform matrix

  • Chrome on Android (Web NFC origin-trial → stable): from the mobile browser or as a PWA.
  • Same JavaScript — the Identity Core API exposes a single /api/v1/nfc/verify-card endpoint.
  • Same contract as native Android: an IsoDep tag and a Web NFC NDEFReader produce the same server payload.
  • iOS Safari has no Web NFC support; iOS uses a CoreNFC bridge (KMP roadmap).
  • Desktop — USB NFC reader (e.g. ACR122U) over loopback or a WebUSB bridge.
06

spoof-detector — Hybrid PAD, Session Verdict, In-Browser

Submodule · MIT · paper draft · iBeta L1 submission · amispoof.fivucsas.com

GPU-less, two ways. spoof-detector runs without a GPU on both sides: server-side (Python reference, Hetzner CX43 CPU, 63 ms / frame, 15.9 fps) and client-side (browser WASM bundle, optional WebGPU, 25–30 fps on desktop). This architectural choice frees both the FIVUCSAS SaaS deployment and any self-hosted environment from any GPU dependency.

spoof-detector is a separate submodule (git@github.com:Rollingcat-Software/spoof-detector.git, MIT, published as @rollingcat/spoof-detector v0.2.1). It contains the 19-analyzer hybrid PAD, a 15-axis LivenessProver (185-pt ceiling, natural decay), a session-level peak-sensitive verdict aggregator, and a TypeScript browser port deployed at amispoof.fivucsas.com. The architectural contribution — proven formally in §4 of the paper — is that session verdicts resist spoof-burst dilution: 54 spoof frames at p = 0.20 + 6 real frames at p = 0.95 → verdict SPOOF; an otherwise live session with a single dip frame → verdict LIVE.

A. Architecture

  • Backbone — MiniFASNet ONNX (UniFace v2, frozen, 1.7 MB), 80×80 input, P(REAL) ∈ [0, 100]. Discrimination gap on in-house set +94.7 (μ_real 99.9, μ_spoof 5.1). paper/ARCHITECTURE.md:75-76 · 05_calibration.md:25
  • Session verdict — P_session = α · mean(p_t) + (1 − α) · mean(p_t | t ∈ worst-decile), α = 0.5. Formal proof in paper/sections/04_method.md:62-114.
  • Calibration — 13 linear coefficients in MultiClassFuser, calibrated against 43 KVKK-consented Marmara captures (27 bona-fide + 16 attacks). No model training. 05_calibration.md:66
  • Anti-correlation finding (§5 contribution) — Laplacian-texture & Gabor-moire are anti-correlated on high-PPI AMOLED replays. Re-weighting 1.0 → 0.1 recovers 0.017 of 0.019 AUC gap.
  • LivenessProver — 15 axes (blink, motion, rotation, expression, temporal, gaze, pose, behaviour, optional hand, optional audio). Decays naturally on stale signal. README.md:159

B. Paper

Beyond Single Frames: Session-Based Hybrid Image-and-Video Face Anti-Spoofing with Calibrated Multi-Class Fusion. 10-section manuscript (abstract / intro / related-work / taxonomy / method / calibration / experimental-setup / results / ablations / discussion / conclusion) at paper/sections/*.md.

Target venues — BIOSIG 2026 (Darmstadt, September), IJCB 2026, IEEE FG 2027. paper/README.md:71-74

iBeta PAD Level 1 submission package — commit cc73cf08, 2026-05-11. PAI coverage: bona-fide ✓, print ✓, replay partial (open challenge), 3-D mask routed-not-validated, morphing out-of-scope. iBeta_PAD_Level1_Submission_Package.md:7-11

Analyzer stack — 19 in total

MiniFASNet (image)
w = 5.0 · gap +94.7
Device Boundary
w = 2.5 · gap +19.2
Texture (Laplacian)
w = 0.1 · anti-correlated
Moire (Gabor)
w = 0.1 · anti-correlated
AR-Filter
w = 0.3 · MediaPipe blendshapes
Blink / EAR (temporal)
w = 0.5
rPPG
w = 0.0 (calibration off)
Screen-Replay
w = 0.5
Micro-Tremor
w = 2.5
Landmark Variance
w = 2.0
Temporal
w = 0.3
Background Grid
w = 1.5 · 8×6 cells
Screen Flicker
w = 3.0
Eyebrow motion
browser-only
Blink symmetry
browser-only
Gaze tracker
browser-only
Expression dynamics
browser-only
3-D Pose consistency
browser-only
Behavioural pattern
browser-only

Measured results (paper, bootstrap 95 % CI on 100 stratified resamples)

Dataset / regimePipelineValue95 % CISource
CASIA-FASD AUC (zero-shot, N = 2 408)minifasnet_only0.9452[0.9366, 0.9560]07_results.md:15
CASIA-FASD ACERminifasnet_only12.67 %[11.07, 13.92]:15
CelebA-Spoof AUC (zero-shot, N = 2 611)minifasnet_only0.7818[0.7663, 0.7993]:36
CelebA-Spoof ACERminifasnet_only28.67 %[27.36, 30.23]:36
In-house replay AUC (N = 100)image_only0.9264[0.8685, 0.9744]:68
Cross-dataset CI separationminifasnet_only0.14 AUC pts> 4 × CI width:42-43
Per-frame latency (Hetzner CX43 CPU)hybrid63.0 msp99 = 117.8 ms:110
Sustained FPS (Python reference)hybrid15.9 fps:110-112
Browser (desktop Chrome, WebGPU)browser bundle25 – 30 fpsBROWSER_READINESS.md:4
Browser (Pixel-class Android, Brave)browser bundle6.7 – 9.5 fpswith Worker frame-skipROADMAP.md:139-141
ISO/IEC 30107-3 (in-house scripted)sessionGrade CBPCER 0 % · APCER 30 % · ACER 15 %README.md:74-84

Honest competitive positioning. The paper does not claim to beat commercial PAD competitors (FaceTec ZoOm, iProov GPA, Onfido Atlas, Jumio, AWS Rekognition Liveness, Microsoft Face API) head-to-head. Modern intra-dataset SOTA (CDCN, FAS-SGTD) reaches AUC > 0.99 with full retraining; FIVUCSAS's 0.9452 is zero-shot — competitive with mid-tier published methods on the strictest robustness regime. Where FIVUCSAS does hold genuine ground: session-level verdicts (proctoring-native), client-side browser deployment (no GPU server, no frame upload), the anti-correlated signal discovery, reproducible no-training calibration (13 floats), MIT open-source. Where it does not yet: model maturity (frozen 3rd-party backbone), dataset scale (43-sample in-house calibration).

Browser port. TypeScript port (spoof-detector/web/), 123 kB ESM / 34 kB gzip + 3 lazy chunks (Texture 7.9 kB · Moire 10.5 kB · ScreenReplay 18.2 kB) + 30 kB Worker. Runtime deps lazy-loaded from CDN: onnxruntime-web 1.18 (WASM + WebGPU fallback, feature-detected), @mediapipe/tasks-vision 0.10.18. Model assets cached forever (Cache-Control: max-age=31536000, immutable). 217 vitest tests green.

07

The Biometric Puzzle — 23 Micro-Challenges

14 face + 9 hand-gesture · server-nonced · replay-proof · canonical enum BiometricPuzzleId

The active liveness layer is a collection of 23 canonical micro-challenges the user performs with face or hand biometrics (web-app/src/features/biometric-puzzles/BiometricPuzzleId.ts). Per attempt the server selects a random sequence of 2–7 challenges, signs it with a UUID v4 nonce (Redis), assigns a difficulty tier and sends it to the client. The client streams only landmark and metric vectors — the server classifies each step against EAR / MAR / yaw thresholds and signs the verdict. Pre-recorded video, AR filters, deepfake injection and screen-replay all fail because the requested sequence is unpredictable and unmodifiable client-side.

14 Face Micro-Challenges

FACE_BLINK
EAR 0.21 / 0.23
CLOSE_LEFT
L-EAR drop
CLOSE_RIGHT
R-EAR drop
SMILE
corner-raise 0.05
OPEN_MOUTH
MAR · 0.6
TURN_LEFT
yaw −20°
TURN_RIGHT
yaw +20°
LOOK_UP
pitch +12°
LOOK_DOWN
pitch −12°
RAISE_BOTH_BROWS
eye-brow Δ 0.08
RAISE_LEFT_BROW
L-brow Δ
RAISE_RIGHT_BROW
R-brow Δ
NOD
pitch oscillation
SHAKE_HEAD
yaw oscillation

9 Hand-Gesture Micro-Challenges (landmark-only — no image upload)

FINGER_COUNT
TIP/PIP ratio
WAVE
wrist-x zero-cross
FLIP
palm-normal sign
FINGER_TAP
idx ↔ mid proximity
PINCH
thumb ↔ idx distance
PEEK_A_BOO
monotonic cover
MATH (n=k)
random open-fingers
SHAPE_TRACE
DTW vs template
TRACE_TEMPLATE
DTW catalog

A. Sequence & timing

  • Difficulty: easy (2–3 actions, 7 s each) · standard (3–4 / 5 s) · hard (4–5 / 4 s). app/domain/entities/puzzle.py:14-19
  • Step count: randomised 2–7 · per-step timeout 2–30 s · max 3 retry · session timeout 120 s.
  • Total TTL: 5 minutes · puzzle UUID stored in Redis.
  • Entropy: 23 P k permutations for length-k sequences. For a single 4-step puzzle ≈ 212 520 ordered sequences.

B. Anti-replay & hybrid fusion

  • Sequence is generated server-side; client cannot mutate it.
  • UUID v4 nonce + expires_at = created_at + 5 min; expired puzzle is rejected. puzzle.py:73, 87-97
  • Optional Base64 spot-check frames re-verified by server. puzzle.py:100-101
  • Pre-recorded video → mismatched sequence; deepfake / AR filter → blendshape inconsistency; screen-replay → moire / micro-tremor signal.
  • LIVENESS_MODE ∈ {passive, active, combined}, default combined. Fusion rule: accept iff min(Pactive, Ppassive) ≥ θ
08

Ten Composable Authentication Factors

NIST 800-63B · Know / Have / Are / Show · tenant JSON, not Java
∑ 10
Per-tenant MFA composition · no backend code required
Know
Password
BCrypt-12
PasswordAuthHandler.java
Have
Email OTP
6-digit · 5 min
OtpService.java:16
Have
SMS OTP
Twilio · 6-digit
SmsOtpAuthHandler.java
Have
TOTP
RFC 6238 · 30 s
TotpService.java:32
Have
QR Code
cross-device
QrCodeAuthHandler.java
Are
Face
Facenet-512 + Puzzle
FaceAuthHandler.java
Are
Voice
Resemblyzer · 256-D
V33 voice_enrollments
Are
Fingerprint
WebAuthn platform
FingerprintAuthHandler.java
Have
Hardware Key
FIDO2 · WebAuthn
HardwareKeyAuthHandler.java
Show
NFC Document
ICAO 9303 · BAC
NfcDocumentAuthHandler.java
8.5

Self-Host or SaaS · GPU-less by Design

Open source · install in your own infra · no GPU dependency anywhere

A. Two delivery models — your choice

  • SaaS (managed) — like Marmara University: hosted login on verify.fivucsas.com, zero operational burden, shared Hetzner CX43. For teams who would rather we operate it.
  • Self-host (on-prem / private cloud) — open source, single-machine Docker Compose install. Same operating model as PostgreSQL, OpenWebUI, Keycloak, Authentik, Supabase. For banks, public sector and KVKK / GDPR-local deployments.
  • Hybrid — control plane (Identity Core) on the tenant side, ML services (Biometric Processor + spoof-detector) in the FIVUCSAS cloud. Network egress is limited to Fernet-encrypted embeddings.
  • Licensespoof-detector is MIT-public; the main monorepo opens on the Spring 2026 roadmap, alongside paper publication.

B. GPU-less — by design, not by accident

Hetzner CX43 is a single rented physical machine — 8 vCPU / 16 GB / 150 GB / no GPU. On that one box, 7 production containers + Postgres + Redis + Prometheus + Grafana + Loki + the 19-analyzer hybrid PAD + MediaPipe FaceLandmarker + DeepFace + Facenet-512 + the MiniFASNet ONNX backbone all run CPU-only. Self-hosters inherit the same property — modest commodity hardware is enough.

  • Boot sentinel: ALLOW_HEAVY_ML=false by default refuses to boot with retinaface, yolov8 – 12, ArcFace, VGG-Face or GhostFaceNet.
  • The spoof-detector browser port uses WebGPU when available but falls back to WASM for 100 % CPU-only operation; native Chrome runs 25–30 fps with WebGPU, 8–12 fps via the WASM Worker with frame-skip.
  • Architectural achievement: a GPU-free environment hosts the 23-puzzle active liveness, the 19-analyzer passive PAD, Facenet-512, ICAO 9303 NFC, ten composable auth factors and a multi-tenant SaaS — all on one box.

C. Paper scope — whole-project or spoof-detector-only?

The current paper draft ("Beyond Single Frames: Session-Based Hybrid Image-and-Video Face Anti-Spoofing with Calibrated Multi-Class Fusion") is spoof-detector–focused and targets BIOSIG 2026 / IJCB 2026 / IEEE FG 2027. Alternative scope: "FIVUCSAS — A GPU-less, Multi-Tenant Biometric Identity SaaS with Hybrid Active + Passive Liveness, 23 Active Micro-Challenges, ICAO 9303 NFC Two-Rail Architecture, and a Drop-in OIDC Button" — a whole-system / system-design paper for ICSE, ICST, ASE or an industry-track venue. The decision will be made once the current draft is finalised.

09

Differentiators & Engineering Effort

What we delivered · what was actually hard

A. What we delivered

  • Production multi-tenant SaaS — Marmara Üniversitesi live (demo.fivucsas.com) · 7 prod containers on Hetzner CX43.
  • Hexagonal / DDD — ports/adapters in both Java (identity-core) and Python (biometric-processor).
  • OAuth 2.0 + OIDC + PKCE — discovery, JWKS, RS256 JWT default (flipped 2026-04-20).
  • 10 composable auth factors — every one wired to its own handler.
  • Postgres RLS on 9 tables (V25) + audit-log partitioning by tenant (V40 + pg_partman V57).
  • Encryption at rest — Fernet AES-128 + HMAC-SHA256 for embeddings; AES-128 for TOTP secrets (V31).
  • WebSocket proctoring wire protocol — per-frame analysis, incident ledger, ProctorMetrics.
  • spoof-detector browser port — 19 analyzers + 15-axis LivenessProver shipped to amispoof.fivucsas.com.
  • NFC native pipeline — Android IsoDep + BouncyCastle + ML Kit OCR + DG2 ↔ live-selfie cosine match.
  • Shared UI component library (DRY)app.fivucsas.com and verify.fivucsas.com share one design system: colours, buttons, form inputs, modals and the biometric-enrolment flow are written once and ship to both products. UI updates propagate from a single source.
  • ~691 k lines · ~2 768 tests · ~1 847 commits (last 6 months, all repos).

B. What was actually hard (honest engineering log)

  • Cross-modal timing — Puzzle ↔ PAD fusion; fail-open cosine bug in FaceVerifyMfaStepHandler closed in PR #83.
  • MediaPipe Tasks-API port — migrated from legacy face_mesh (active branch fix/2026-05-12-mediapipe-tasks-api-port).
  • pgvector index tuning — IVFFlat (lists = 100) vs HNSW (m = 16 / ef = 64). Recall-vs-latency calibration ongoing.
  • Postgres RLS + audit-log partitioning — V57 silently no-op'd until V59 / V60 backfill of 140 NULL tenant_ids.
  • BAC crypto correctness — SHA-1 key derivation from MRZ; PACE / AA / CA still out-of-scope.
  • FK-cascade incidentDELETE FROM users wiped a real user's TOTP / WebAuthn / NFC; patched to soft-delete-aware findByEmail.
  • Anti-correlated signal discovery — texture / moire higher on real in modern hi-PPI capture (paper §5).
  • Browser readiness phases A–D — WebGPU fallback, Worker offload, lazy chunks, 217 vitest CI gating.
  • KVKK irreversibility framing — Fernet is reversible with the key; framing changed to operational not mathematical.
  • Liveness mode wiring — hybrid mode demands active sequence; /verify only sends one still → use passive + uniface for single-frame verdicts.
10

Subdomain Ecosystem

9 subdomains · 1 QR · all behind Traefik v3.6
fivucsas.com
Landing site
Product marketing + entry point. Hosted at Hostinger; 301 from www.
verify.fivucsas.com
Hosted login & widget
Redirective OIDC login (primary) + iframe step-up MFA for sensitive operations.
api.fivucsas.com
Identity Core API
OAuth 2.0 issuer · OIDC discovery · /.well-known/jwks.json · userinfo · 10 auth factors.
app.fivucsas.com
Admin console
Tenant config, user management, enrollment / verification logs.
demo.fivucsas.com
Marmara BYS demo
Live tenant: student identity verification + exam proctoring demo.
docs.fivucsas.com
Documentation
Integration guide · API reference · architecture docs · SDK examples.
status.fivucsas.com
Uptime monitor
Public service-health page (UptimeRobot) — API + biometric + verify widget.
amispoof.fivucsas.com
Spoof-detector demo
19-analyzer PAD running entirely in the browser: WebGPU + WASM, no frame uploads. 217 vitest green.
Grafana [internal-only]
Observability container
Prometheus + Loki dashboards. Docker container fivucsas-grafana runs; Traefik public router is commented out (infra/traefik/config/dynamic.yml:103) and no public DNS — accessible only from within the host.

One QR · all links. A single QR code on this poster points to a link navigator page we own: links.fivucsas.com. We do not depend on a third-party shortener — our own static subdomain hosts every project subdomain, the team (GitHub, LinkedIn, portfolio, email), poster artefacts (HTML, PDF, PNG, text brief) and shortcuts to live surfaces. Hostinger static (no Docker), the same pattern as bys-demo / amispoof / landing.

FV
One QR · all links

Scan to open the FIVUCSAS hub

A single QR for landing + hosted-login + admin + docs + demo + spoof-detector + status — every surface under one short link. Scan from any phone and jump to the surface you need.

https://fivucsas.com/links

11

By the Numbers

Measured 2026-05-19 · all values from repo, no estimates
~691k
Lines of code · all 12 submodules
~2 768
Automated tests (Java + Py + TS)
~1 847
Commits last 6 months · all repos
60
Flyway migrations · V1 → V60
10
Composable auth factors · all wired
19
Spoof analyzers fused at session level
23
Biometric puzzle micro-challenges
0
GPUs required · CPU-only stack
512
Facenet-512 embedding dimension
9
Tables with Postgres RLS (V25)
217
Browser bundle vitest green
63ms
Per-frame PAD latency · CX43 CPU

Per-submodule LOC: spoof-detector 217k · practice-and-test 222k · client-apps 89k · biometric-processor 77k · landing 26k · identity-core-api 28k · web-app 15k · verify-widget 7.8k · others 5.5k. Tests: Spring 944 · Pytest 265 · Vitest / Jest 1 559. Encryption: Fernet AES-128 + HMAC-SHA256 (embeddings) · AES-128 (TOTP secrets) · BCrypt-12 (passwords) · RS256 JWT.

12

Frequently Asked Questions

12 short answers · ≤ 45 words each
What problems does FIVUCSAS solve?
It removes the requirement to register and log in to every web/mobile app. With one FIVUCSAS button, users sign in anywhere FIVUCSAS is supported using any of ten methods. App owners ship hosted-login via OIDC + PKCE without writing register/login pages.
How is it different from e-Devlet?
e-Devlet is Türkiye's public-sector SSO; FIVUCSAS offers the same drop-in button to the private sector. Open OIDC discovery, ICAO 9303 NFC, active Puzzle + passive PAD, multi-tenant RLS, KVKK + GDPR + ISO 30107-3 L1 submission package.
Why ten composable authentication factors?
Following NIST 800-63B's Know / Have / Are / Show axes, each tenant composes its own MFA flow from the supported set — no backend code required, configuration is JSON. A bank and a small SaaS reuse the same code path with different combinations.
How does the Biometric Puzzle catch spoofs?
The server emits a UUID-nonced sequence of 3–5 random actions per attempt (5-min TTL). Pre-recorded video, deepfake injection and screen-replay all fail because the requested action set is unpredictable, timestamped, server-generated and immutable client-side.
How is KVKK / GDPR compliance achieved?
Embeddings are sealed at rest with Fernet AES-128 + HMAC-SHA256. Soft-delete via deleted_at + Hibernate @SQLRestriction. Postgres RLS on 9 tables (V25). Audit logs partitioned by tenant_id (V40 + pg_partman V57). EU/TR-accessible Hetzner hosting.
What does it add to proctoring?
A session-level peak-sensitive verdict (α = 0.5, mean + worst-decile) with a formal proof of resistance to spoof-burst dilution. A 15-axis LivenessProver runs continuously; 63 ms / frame Python reference, 25–30 fps in-browser (WebGPU). Background-grid analyzer is proctoring-specific.
Is NFC mandatory?
No — it is an optional factor. For bank-grade KYC it adds physical-document verification via DG2 face JPEG2000 ↔ live selfie cosine match. Supports Turkish T.C. ID + ICAO 9303 passports (BAC); simple ISO 14443 cards over Web NFC require no native layer.
Active Puzzle vs passive PAD — what is the difference?
Passive (UniFace MiniFASNet + 18 auxiliary analyzers): silent, no user cooperation. Active (Puzzle): the user performs server-requested actions — replay-proof. Hybrid fusion rule: accept iff min(Pactive, Ppassive) ≥ θ.
Where is the spoof-detector research published?
MIT submodule at github.com/Rollingcat-Software/spoof-detector; manuscript skeleton in paper/sections/*.md targeting BIOSIG 2026 / IJCB 2026 / IEEE FG 2027. Live browser demo at amispoof.fivucsas.com. iBeta PAD-L1 submission package on commit cc73cf08.
Do you have in-house EER / FAR / FRR numbers?
For the face pipeline, no in-house measurement yet — we say this honestly. Published Facenet-512 rates apply. For the spoof-detector, CASIA-FASD AUC 0.9452 (zero-shot, 95 % CI [0.94, 0.96]) and ACER 12.67 % were measured.
Does the system need a GPU?
No. A single Hetzner CX43 (8 vCPU / 16 GB / no GPU) runs all 7 services + 23-puzzle active liveness + 19-analyzer passive PAD + Facenet-512 + NFC pipeline. The boot sentinel ALLOW_HEAVY_ML=false refuses any GPU-only model. Self-hosters inherit the same property.
Can I self-host on my own infrastructure?
Yes — a single Docker Compose command. Same operational model as PostgreSQL, OpenWebUI, Keycloak, Authentik or Supabase. spoof-detector is already MIT-public; the main monorepo opens in Q4 2026 alongside paper publication. SaaS at verify.fivucsas.com for those who prefer hosted.
13

Technologies & References

Stack · standards · bibliography

Stack

Spring Boot 3.4 Java 21 FastAPI Python 3.12 Kotlin Multiplatform Jetpack Compose React 18 · Vite Material UI Android NFC · IsoDep Bouncy Castle Google ML Kit OCR PostgreSQL 17 · pgvector Redis 7.4 OpenCV MediaPipe Tasks TensorFlow · DeepFace · Facenet-512 UniFace MiniFASNet (ONNX) onnxruntime-web · WebGPU Resemblyzer (voice) Traefik v3.6 Docker · Compose Hetzner CX43 · Ubuntu 24.04 Prometheus + Grafana + Loki JWT · RS256 · OAuth2 · OIDC · PKCE OpenAPI 3.1 · Swagger JUnit · k6 / JMeter GitHub Actions · self-hosted runner Twilio Verify Flyway · Alembic

Standards & references

  • ICAO Doc 9303 — Machine Readable Travel Documents (8th ed.).
  • ISO/IEC 30107-3:2017 — Biometric Presentation Attack Detection — Testing & Reporting.
  • NIST SP 800-63B — Digital Identity Guidelines — Authentication & Lifecycle.
  • RFC 6749 — The OAuth 2.0 Authorization Framework.
  • RFC 7636 — Proof Key for Code Exchange (PKCE).
  • RFC 6238 — TOTP: Time-Based One-Time Password Algorithm.
  • OpenID Connect Core 1.0; Discovery 1.0.
  • W3C Web Authentication Level 3 (WebAuthn / FIDO2).
  • Schroff, Kalenichenko, Philbin (2015). FaceNet: A unified embedding for face recognition and clustering. CVPR.
  • Zhang et al. (2012). A face antispoofing database with diverse attacks. ICB.
  • Zhang et al. (2020). CelebA-Spoof: Large-scale face anti-spoofing dataset with rich annotations. ECCV.
  • UniFace MiniFASNet (community ONNX release, used as frozen backbone).
  • FIVUCSAS spoof-detector — internal paper draft, 10 sections, target BIOSIG 2026.
Repositories

github.com/Rollingcat-Software/fivucsas (private)
github.com/Rollingcat-Software/spoof-detector (MIT)
6 git submodules · 1 self-hosted runner

Live surface

fivucsas.com · verify.fivucsas.com · demo.fivucsas.com
api.fivucsas.com · app.fivucsas.com · docs.fivucsas.com
amispoof.fivucsas.com · status.fivucsas.com

Contact

ahmetabdullahgultekin@gmail.com
aysegulsumeren@gmail.com
aysenurarici@hotmail.com
Supervisor · ağaoğlu @ marmara.edu.tr

FIVUCSAS · Marmara Üniversitesi · CSE4297 / CSE4298 Engineering Project · Spring 2025 – 2026 · A0 poster v3 · evidence-pinned 2026-05-19 · every metric cited to file:line — see POSTER_BRIEF.md at repo root for full source map.