Zero-Ceremony Identity: Why I Built a Single-Binary OIDC Provider in Go

Published: (March 26, 2026 at 07:44 PM EDT)
3 min read
Source: Dev.to

Source: Dev.to

The problem with existing solutions

Identity infrastructure is notoriously complex. A typical self‑hosted setup involves:

  • A database server
  • A cache tier (e.g., Redis)
  • A worker queue
  • The identity service itself

Running a lightweight OIDC server on a small 2 GB RAM VPS quickly revealed that the existing landscape was either operationally exhausting or structurally flawed for my needs.

What I found lacking

ProviderIssue
CasdoorDemo instances recycle accounts every 5 minutes, making it impossible to test account deletion.
PocketIdPasskey‑only by default. Users on older OSes or restrictive browsers would be locked out.

These roadblocks pushed me to convert my OIDC protocol server (originally built for a frontend library at work) into a full IdP, constantly asking: Does this reduce or increase the operational burden on the operator?

Auténtico’s design principles

  • Single binary – The entire IdP runs as one Go binary.
  • Embedded SQLite – All state lives in a single file; no external DB server, eliminating connection‑pool tuning, credential rotation, and network partitions.
  • Zero external infrastructure – No Redis, Postgres, or message queues. Background goroutines automatically purge expired tokens, sessions, and auth codes.
  • Embedded UIs – Admin dashboard (React/Ant Design) and user‑facing Account UI (React/Tailwind) are compiled into the binary via go:embed. No separate frontend deployments.

Flexible authentication modes

Auténtico offers three runtime‑switchable authentication modes (no restart required):

  1. password
  2. password_and_passkey
  3. passkey_only

If a deployment using passkey_only encounters browser incompatibilities, an admin can instantly flip a setting in the Admin UI to fall back to passwords. Additional fallback methods include:

  • TOTP (in‑browser QR enrollment)
  • Email OTP
  • Hardware‑backed FIDO2 authentication (with seamless first‑login registration)

Vertical‑slice architecture

The codebase follows a strict vertical‑slice layout, where each package owns its slice of functionality:

pkg/login/
    model.go
    handler.go
    service.go
    // Database CRUD

This disciplined structure:

  • Keeps the code “deliberately un‑clever,” making it easy for AI assistants to generate boilerplate.
  • Enabled rapid creation of > 700 tests, achieving ~80 % coverage.

Performance & scalability

SQLite serializes writes, so Auténtico is not meant for active‑active multi‑region deployments. The performance envelope is nevertheless generous for internal tools and small‑to‑mid‑size apps.

Concurrent VUsError rateLogin p95Token p95Verdict
200 %86 ms54 msComfortable – imperceptible
1000 %611 ms647 msSupported – fully functional
5000 %3.36 s3.89 sDegraded – noticeable latency

Tests were run with k6; SQLite’s busy timeout queues requests, adding latency instead of throwing errors.

For most teams, trading infinite horizontal scaling for zero operational overhead is the right choice.

Feature checklist

  • OIDC Discovery – Publishes /.well-known/openid-configuration.
  • JWK Set – Exposes public signing keys at /.well-known/jwks.json.
  • RS256 JWT signing – Asymmetric signing; the private key never leaves the IdP.
  • OAuth2/OIDC protocol implementation.
  • Admin UI – Manage clients, users, and sessions.
  • Account UI – Users manage their profile.
  • Swagger/OpenAPI docs – API specifications are published automatically.

Who should consider Auténtico?

  • Small teams or indie developers needing an Identity Provider without a dedicated sysadmin.
  • Organizations running internal tools, self‑hosted environments, or modest‑scale applications where operational simplicity outweighs massive horizontal scaling.

GitHub:

0 views
Back to Blog

Related posts

Read more »

Stop picking my Go version for me

The go.mod file contains a mandatory go directive. Since Go 1.21, when a change was introducedhttps://go.dev/doc/go1.21introduction to make this include a full...