esc
The Great Unbundling
The V3 Saga

The Great Unbundling

Previously on Lifelog... The Polishing Daemon had done its work. Eight fixes. The blog existed properly. But in the shadows, a dependency lurked. A middleman. A toll booth on the road to your own...

December 2, 2025

Previously on Lifelog…

The Polishing Daemon had done its work. Eight fixes. The blog existed properly. But in the shadows, a dependency lurked. A middleman. A toll booth on the road to your own data.

Cloudflare Zero Trust. Good intentions. Excellent security. But every login, every request, every moment—routed through someone else’s authentication. The lifelog lived, but it lived on someone else’s terms.

Tonight, we cut the cord.

00:20 — The Revelation

“Can we add native Google Sign-In?”

The question hung in the air. Simple words. Monumental implications. JWT. OAuth2. Bearer tokens. Cookie security. The whole authentication stack, rewritten.

“It’s probably a day’s work,” said the reasonable voice.

75 minutes later, we were in production.

The Speedrun

00:25 — JWT utilities materialized. Secret generation. Token validation. 30-day expiry. The skeleton of authentication.

00:32 — Google OAuth handler born. Login page. Callback. Logout. The dance with Google’s servers choreographed in Go.

00:38 — First bug. email_verified vs verified_email. Google’s API v2 speaks in snake_case riddles. Fixed.

00:42 — “Did you remember we have one SQLite file per user?” The cold sweat moment. O(n) token lookups. Unacceptable.

00:48 — Global token store. global.db at the Manager level. O(1) lookup. The architecture bends to the requirement.

00:55 — Bearer tokens for CLI/API/MCP. Create. Copy. Revoke. The Settings UI grows a new section.

01:05 — The old Cloudflare middleware deleted. 44 lines of history, vanishing into git’s memory.

01:15 — “But wait—we need two domains. Public blog. Private app.”

01:22 — Domain-based routing. Single port. Host header inspection. app.lifelog.my → auth required. lifelog.my → public. localhost → dev convenience.

01:35 — Deployed. Tested. Working.

The New Architecture

lifelog.my          → Public landing + blogs (no auth)
lifelog.my/riclib/  → Your posts, for the world
app.lifelog.my      → Private app (Google OAuth)

One port. Zero middlemen. Your data, your auth, your terms.

The Tally

  • 1,379 lines added
  • 3 new files in internal/auth/
  • 1 global token database
  • 1 domain router
  • 0 external auth dependencies
  • 75 minutes, start to finish

The Cloudflare Access application was deleted. The toll booth demolished. The road now runs direct.

Some nights you polish. Some nights you productise.

Tonight was a productising night. 🚀


See also:

The Saga (in which dependencies are cut):

The References (auth independence):