Skip to content

GoPlausible/liquid-auth-cloud

Repository files navigation

Liquid Auth Cloud

@goplausible/liquid-auth-cloud

Liquid Auth on Cloudflare Workers — passwordless FIDO2/WebAuthn authentication with Algorand wallet binding, deployed to the edge with zero idle cost.

Built by GoPlausible, inspired by the Algorand Foundation's Liquid Auth reference server. A ground-up reimplementation that replaces NestJS + MongoDB + Redis + Docker with Cloudflare Workers + KV + Durable Objects — lighter, more scalable, cloud-native, and serverless.

Live deployment: https://liquidauth.goplausible.xyz

Related Projects

Project Package / App Description
Liquid Auth Client (TypeScript) @goplausible/liquid-client Browser client — native WebSocket, FIDO2 + WebRTC signaling
Liquid Auth Android Android wallet app FIDO2 + WebRTC with native OkHttp WebSocket
Rocca Wallet React Native / Expo app Cross-platform wallet — FIDO2 passkeys + WebRTC
WebRTC Payment SDK @goplausible/webrtc-payment-sdk Used in — micropayment-gated WebRTC streams on Algorand

What Makes This Different

Concern Original (NestJS) This (Cloudflare Workers)
Runtime Node.js + Express + Docker Cloudflare Worker (V8 isolate)
User storage MongoDB Workers KV
Sessions MongoDB + connect-mongo Durable Object with HMAC-SHA256 signing
WebSocket Redis + Socket.io Durable Objects + native WebSocket
Crypto Node.js crypto tweetnacl + Node crypto (nodejs_compat)
Static assets Express static Worker assets + R2 bucket
Deployment Docker / VM wrangler deploy
Scaling Manual / load balancer Automatic edge scaling, 300+ PoPs
Idle cost Server always running Zero (pay per request)

Key design choices:

  • No Socket.io — native WebSocket with { event, data } JSON protocol, designed for Durable Object Hibernation API
  • Room routing via URL/ws?requestId=xxx puts both peers in the same DO instance without room-join handshakes
  • Dual room broadcast — auth events go to both the wallet room and the requestId room so the offer peer always receives them
  • Discoverable assertions — supports passwordless sign-in without knowing the credential ID (synced passkeys across devices)
  • Proper SHA-512/256 — Algorand address checksums use real SHA-512/256 via Node crypto, not truncated SHA-512

How It Works

  Wallet (FIDO2)                  Cloudflare Edge                    Browser/Dapp
  ==============           =========================          ==================

  1. Scan QR code  ------>     Worker receives request
                               KV stores challenge
                               Returns attestation options

  2. Sign with passkey ----->  Worker verifies attestation
                               KV stores user + credential
                               DO broadcasts auth event
                                         |
                                         v
                               WalletRoom Durable Object -------> WebSocket push
                               (per-requestId signaling room)     "link" event

  3. WebRTC signaling  <-----> DO relays offer/answer  <-------> WebRTC signaling
     (offer/answer/ICE)        candidates between peers          (offer/answer/ICE)

  4. DataChannel opens <======= encrypted P2P ==================> DataChannel opens

Getting Started

Prerequisites

  • Node.js >= 18, npm
  • Wrangler CLI (npm install -g wrangler)
  • A Cloudflare account

Local Development

# From the monorepo root
npm install
npm run dev:cloud         # Starts at http://localhost:8787

Deploy

npm run deploy:cloud

Configuration

Update wrangler.toml:

[vars]
RP_NAME = "Your App Name"
HOSTNAME = "auth.yourdomain.com"
ORIGIN = "https://auth.yourdomain.com"
ANDROID_ORIGINS = "android:apk-key-hash:<YOUR_APK_KEY_HASH>"
SESSION_TTL = "300"

Set secrets:

wrangler secret put SESSION_SECRET

Routes

Pages

Route Description
GET / Demo page — offer side, QR codes, messaging
GET /wallet?requestId=xxx Web wallet — mobile-optimized answer side
GET /.well-known/assetlinks.json Android FIDO2 Digital Asset Links
GET /download/:key Serve files from R2 (APK, assets)
GET /favicon.ico Served from Worker static assets

FIDO2 Registration (Attestation)

Route Description
POST /attestation/request Get WebAuthn registration options
POST /attestation/response Submit signed attestation with Liquid extension

FIDO2 Authentication (Assertion)

Route Description
POST /assertion/request Discoverable assertion (no credId — synced passkeys)
POST /assertion/request/:credId Assertion for a specific credential
POST /assertion/response Submit signed assertion

Session Management

Route Description
GET /auth/session Current session and user info
GET /auth/user Authenticated user (401 if not logged in)
DELETE /auth/keys/:credId Remove a credential
GET /auth/logout Destroy session, redirect to /

WebSocket Signaling

const ws = new WebSocket(`wss://auth.yourdomain.com/ws?requestId=${requestId}`);

// All messages use { event, data } JSON envelope
ws.send(JSON.stringify({ event: "link", data: { requestId } }));

ws.onmessage = (e) => {
  const { event, data } = JSON.parse(e.data);
  // event: link | offer-description | offer-candidate | answer-description | answer-candidate
};

Project Structure

src/
  index.ts          Entry point, routing, CORS, session cookies
  types.ts          Env bindings, StoredUser, StoredSession, events
  encoding.ts       Base64URL, Base32, SHA-512/256, Algorand address codec
  kv.ts             KV storage layer (users, credentials)
  session.ts        Session utilities (HMAC-signed cookies)
  session-store.ts  SessionStore Durable Object
  fido2.ts          FIDO2 attestation/assertion, Liquid extension verification
  wallet-room.ts    WalletRoom Durable Object (WebSocket signaling)
  routes.ts         HTTP route handlers
  demo.ts           Demo page HTML
  wallet.ts         Web wallet page HTML
public/
  favicon.ico       Static asset

Security

  • No private keys on server — all Algorand signing happens on the client device
  • FIDO2 user verification required — all operations require biometric/PIN
  • Proper SHA-512/256 — Algorand address checksums use the correct algorithm (not truncated SHA-512)
  • Rekeyed account support — checks on-chain auth-addr on both mainnet and testnet
  • Cross-platform origins — FIDO2 origin validation includes both web and Android origins
  • HMAC-SHA256 sessions — stored in Durable Object, signed cookies, automatic TTL expiry
  • HttpOnly + Secure + SameSite=None cookies
  • No workers.dev URL — custom domain only, workers_dev and preview_urls disabled
  • Secrets encrypted at restSESSION_SECRET set via wrangler secret put

Documentation

  • Architecture — component design, data flow, migration mapping
  • Sequence Diagrams — registration, authentication, WebSocket, session flows
  • Vision — why edge deployment, principles, design decisions
  • Contributing — development setup and guidelines

License

MIT — see LICENSE.

About

This is a redesigned and revamped version of Algorand Foundation Liquid Auth for cloud and edge implementations instead of relying on server or docker environments

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors