A minimal self-hosted passkey server for existing applications.
Website · Documentation · Releases · Commercial support
One binary. One JSON configuration file. One PostgreSQL database. Built in Go. No IAM platform and no vendor cloud.
Your application keeps its users, sessions and login decisions; Shellty handles passkey registration and authentication.
Registration, authentication, credential management, PostgreSQL history, native HTTPS/mTLS, embedded migrations and health/readiness.
You'll need Go 1.27, PostgreSQL and TLS certificates. Start with local development for database and certificate setup. The database role needs DDL permissions for startup migrations.
Copy config.example.json to config.json and set your
application's RP ID, origins and client certificate fingerprint. Then, from the
repository root:
go run ./cmd/web \
--listen :8443 \
--config config.json \
--database-dsn 'postgres://passkey_server:password@localhost/passkey_server?sslmode=require' \
--tls-cert server.pem \
--tls-key server.key \
--client-ca client-ca.pemAll three TLS flags are required. Adjust the database DSN and certificate paths to match your setup.
To build the binary:
go build -trimpath -o passkey-server ./cmd/webRun ./passkey-server with the same flags.
POST /v1/registrations/start
POST /v1/registrations/finish
POST /v1/authentications/start
POST /v1/authentications/finish
GET /v1/credentials
DELETE /v1/credentials/{credential}
GET /health
GET /ready
See the API contract for request formats, token lifecycle and errors.
Your backend calls Shellty over mTLS and remains responsible for user authorization and application sessions. The browser talks to your backend.
Every /v1/* route requires a CA-verified client certificate whose leaf fingerprint
is authorized for the requested application. /health, /ready and the optional
administration UI use HTTPS without client certificates; admin pages require a
separate login. TLS terminates in Passkey Server; HTTP proxy certificate headers
are not trusted.
Applications are immutable while the process runs. Every node must use the same configuration and database. The RP is the browser application's domain, not the Passkey Server host.
A small optional read-only administration UI is included for configuration, credentials and history. See administration to enable it and learn how login cookies work.
Want to try it end to end? cmd/demo is a separate local HTTPS application for
registering a passkey and testing authentication. It calls Shellty over mTLS and
needs no database of its own or frontend build step.
See browser demo setup for the command, certificate trust and manual test steps.
go test ./...
TEST_DATABASE_DSN='postgres://passkey_server:password@localhost/passkey_server_test?sslmode=disable' go test -race ./...
go vet ./...Integration tests create a fresh temporary schema per test and drop only that schema on completion. The database role needs schema creation permissions.
Without TEST_DATABASE_DSN, PostgreSQL tests explicitly skip; unit, HTTP, native
TLS and WebAuthn adapter tests still run. An Ed25519 authenticator fixture creates
registrations and signs real assertions. No physical passkey needed.
Need help integrating Shellty into an existing backend, IAM or private environment?