Inspiration

Payments are fast; fraud is faster. We set out to build a trust‑first, drop‑in MFA layer any merchant can add without changing gateways. Our goal: security that appears only when needed and explains why. We are a team of a full-stack developer and a data scientist, and we combined to create something we could be proud of.

What it does

  • One JS snippet watches the checkout form and builds a risk context.
  • If risk is greater than the threshold, it prompts for OTP or basic WebAuthn.
  • Low‑risk transactions sail through; high‑risk ones get verified.
  • A clear “Transaction complete” overlay confirms success.

How we model risk

We evaluate each transaction using a set of simple, interpretable decision rules, each capturing a different dimension of potential fraud:

  • High-value transactions: Large payments are inherently riskier and carry the biggest weight in the score.
  • New device: Transactions from previously unseen devices may indicate account compromise.
  • New location: Geographical anomalies suggest possible fraud or stolen credentials.
  • Suspicious merchant: Certain merchant profiles or previously flagged activity can raise risk.

Each rule contributes a defined number of points to the total risk score.

Formally, let S be the risk score and \( \tau \) the threshold. MFA is triggered if \( S \geq \tau \), keeping verification targeted, transparent, and friction-minimized, while providing a clear rationale for why additional authentication was requested.

Example calculation of the score:

$$[ S = 3 \cdot I(\text{amount} \geq 500) + I(\text{new_device}) + I(\text{new_location}) + I(\text{suspicious_merchant}) ]$$

How we built it

  • Frontend: mfaSystem.js (vanilla JS), safe DOM (no innerHTML), CSP hardening, neon‑styled overlays.
  • Backend: Flask APIs (/api/login, /api/check_mfa, /api/verify_mfa), OTP via secrets (crypto‑secure), HMAC‑bound to user/email, TTL and lockouts, and PBKDF2 password hashing.
  • Risk rules: amount, device hints, merchant flags, and adjustable threshold.

Challenges we ran into

  • CORS preflight and CSP blocking inline scripts.
  • ISO‑8601 “Z” timestamps breaking Python’s fromisoformat.
  • Keeping UI consistent across flows while staying provider‑agnostic.
  • Balancing friction vs. security for “only‑when‑needed” MFA.

Accomplishments that we're proud of

  • True drop‑in snippet with configurable attributes.
  • Cryptographically strong OTPs and hashed passwords.
  • Clean, branded OTP and success popups with safe DOM.
  • Clear, tunable risk logic demonstrated end‑to‑end.

What we learned

  • Minimal integration surface drives adoption.
  • Defense‑in‑depth matters: CSP and rate limiting.
  • Explaining “why MFA” preserves trust; don’t MFA everything.
  • Good DX comes from great tooling, i.e., curl + the Network tab.

What's next for MFA Super System

  • Full WebAuthn passkeys (register/auth endpoints, UX polish).
  • Merchant dashboard for rules, analytics, and webhooks.
  • Provider‑agnostic npm package and typed SDK.
  • Production hardening: TLS, secrets management, rate limiting, audit logs.
  • Fraud insights: anomaly detection, suspicious‑merchant signals.

Final thoughts

The MFA Super System balances security and ease of use. Targeted risk rules trigger authentication only when needed, protecting against fraud while keeping checkout smooth and developer integration simple.

Built With

Share this project:

Updates