Skip to content

Latest commit

 

History

34 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Astral Key

Passkey-first authentication middleware — self-hosted, Web3-ready, NixOS-native

Rust License NixOS SecretSpec

Astral Key is an open-source authentication middleware written in Rust (Axum). It authenticates users with FIDO2/WebAuthn passkeys (Touch ID, Windows Hello, YubiKey) and Web3/SIWE (Ethereum wallet signatures), and issues JWT sessions.

Key differentiator: Astral Key is the only self-hostable auth service that combines passkey-native + Web3 wallet auth + a NixOS deployment module in a single Rust binary backed by SQLite (no external dependencies).


Why Astral Key?

Most auth services sit at one of two extremes:

Extreme Examples Problems
Cloud consumer auth Auth0, Clerk, Firebase Auth You don't control the keys. Passkeys roam through Apple/Google/Microsoft clouds.
Enterprise SSO Keycloak, Authentik, Casdoor Heavy (Java/Go), password-first, own database required.

Astral Key fills the unoccupied middle: lightweight (single Rust binary, ~5MB), passkey-native (no passwords required), Web3-ready (SIWE wallet auth),self-hosted with SQLite storage — deployable via Docker Compose in one line.

Who this is for

  • NixOS homelab operators running multi-service stacks (Grafana, Gitea, n8n, OpenWebUI, Nextcloud) who want one passkey to authenticate across all of them — using Astral Key's SQLite-backed identity store for lightweight self-sovereign auth.
  • DAOs and Web3 communities that want members to authenticate with their Ethereum wallet (SIWE) for gated access to Discourse, governance apps, or treasury dashboards. No email, no password.
  • Privacy-conscious passkey users who want self-hosted passkey roaming — keys live in Astral Key's SQLite database, not in Apple iCloud or Google Password Manager.
  • AI agent platforms that need scoped, revocable session tokens for agent tool access — authenticate once with a passkey, issue short-lived capability tokens to Claude Code, Hermes, or custom agents.

Quick Start

With Docker Compose

git clone https://github.com/reverb256/astral-key.git
cd astral-key
export JWT_SECRET=$(openssl rand -hex 32)
docker compose up -d
curl http://localhost:8080/health

With Nix

nix develop
cargo build --release
JWT_SECRET=$(openssl rand -hex 32) ./target/release/astral-key

With NixOS module (declarative)

# flake.nix
{
  inputs.astral-key.url = "github:reverb256/astral-key";

  # In your host config:
  imports = [ inputs.astral-key.nixosModules.default ];

  services.astral-key = {
    enable = true;
    environmentFile = "/run/secrets/astral-key-env";
  };
}

Features

✅ Implemented

Feature Description
FIDO2 / WebAuthn Passkeys Register and authenticate with platform or roaming authenticators. Full WebAuthn ceremony.
Web3 / SIWE Sign-In with Ethereum (EIP-4361). Multi-chain: Ethereum, Polygon, Arbitrum, Optimism.
JWT Sessions Access tokens + refresh token rotation. Verify endpoint for downstream services.
SQLite Storage Embedded SQLite. No external dependencies. Single binary, single file.
Passkey CRUD List and delete registered passkeys.
Multi-Factor JWT Sessions Access tokens + refresh token rotation. Verify endpoint for downstream services.
Ed25519 Identity Public-key identity management, signature verification, contact graph.
ZK JIT Capability Tokens Ed25519-signed scoped tokens with epoch-based revocation.
API Key Management Argon2id-hashed API keys with prefix format ak_prod_....
OIDC Provider Astral Key as an OpenID Connect identity provider (authorization-code flow + PKCE, EdDSA id_tokens) for oauth2-proxy and other relying parties.

🔜 Coming Soon

Feature Target
SecretSpec integration Declare secrets in secretspec.toml, resolve from any of 15 providers, inject via secretspec run -- astral-key
SOPS provider (planned) Encrypted config files decrypted via SecretSpec, keys resolved through astral-key's auth layer
Vault-compatible endpoint Expose /v1/secret/data/<path> so SecretSpec's existing vault provider can read secrets from astral-key — no SecretSpec fork needed
AI agent tokens Short-lived, scoped, revocable tokens for agent tool access

Architecture

┌──────────────┐     ┌──────────────────┐
│   Client     │────>│   Astral Key     │
│ (Browser /   │     │   (Axum API)     │
│  Wallet)     │<────│   Port 8080      │
└──────────────┘     └──────────────────┘
                          │
                     ┌────┴────┐
                     │  SQLite │
                     │   DB    │
                     └─────────┘

In-memory FIDO2 challenge state (TTL-based HashMap) replaces Redis.
No PostgreSQL, Redis, or Vaultwarden required.

The server authenticates users via passkey or wallet → issues JWT sessions. All data persists in SQLite (single file, no external services).

SecretSpec integration (planned)

⚠️ Aspirational — Not yet implemented. The secretspec.toml shown below does not exist in the repo. Tracked in issue #16. Until implemented, all configuration is via environment variables as shown in Configuration above.

SecretSpec integration would allow Astral Key to resolve secrets from 15+ provider backends via a declarative secretspec.toml:

# (planned) secretspec.toml
[project]
name = "astral-key"

[profiles.default]
JWT_SECRET = { required = true }
DATABASE_URL = { default = "sqlite://./astral-key.db?mode=rwc" }

[profiles.production]
JWT_SECRET = { providers = ["vault://http://vault:8200"] }
DATABASE_URL = { providers = ["vault://http://vault:8200"] }
# (planned)
secretspec run -- astral-key

API Overview

Endpoint Auth Description
GET /health Liveness check
GET /ready Readiness check (database)
GET /api/v1/auth/web3/chains List supported chains
POST /api/v1/auth/web3/nonce Request SIWE nonce
POST /api/v1/auth/web3/verify Verify SIWE signature → JWT
POST /api/v1/auth/fido2/register/options JWT Start passkey registration
POST /api/v1/auth/fido2/register/verify JWT Complete passkey registration
POST /api/v1/auth/fido2/authenticate/options Start passkey authentication
POST /api/v1/auth/fido2/authenticate/verify Complete passkey auth → JWT
GET /api/v1/auth/fido2/credentials JWT List registered passkeys
DELETE /api/v1/auth/fido2/credentials/:id JWT Delete a passkey

Full API reference: docs/api.md


Configuration

All configuration is via environment variables.

# Required
export JWT_SECRET=$(openssl rand -hex 32)

# Optional overrides
export SERVER_HOST=0.0.0.0
export SERVER_PORT=8080
export DATABASE_URL="sqlite:/data/astral-key.db?mode=rwc"
export FIDO2_RP_ID=localhost
export FIDO2_RP_NAME="My App"
export FIDO2_ORIGINS=http://localhost:8080

OIDC provider (identity-provider side)

Enable the OIDC provider to let oauth2-proxy (or any RP) authenticate users with passkeys:

export OIDC_ENABLED=true
export OIDC_ISSUER=https://auth.lan
export OIDC_CLIENT_ID=astral-key-oidc
export OIDC_CLIENT_SECRET_FILE=/run/secrets/astral-key-oidc-client-secret
export OIDC_REDIRECT_URIS=https://auth.lan/oauth2/callback
# 64-hex Ed25519 seed (pin this — the JWKS changes across restarts otherwise)
export OIDC_SIGNING_KEY_FILE=/run/secrets/astral-key-oidc-signing-key

Endpoints (all relative to the issuer root):

Endpoint Description
/.well-known/openid-configuration OIDC discovery document
/.well-known/jwks.json Ed25519 signing key (JWKS)
/oidc/authorize Authorization endpoint (GET: login page, POST: code issue)
/oidc/token Token endpoint (authorization-code + PKCE)
/oidc/userinfo Userinfo endpoint

The first user is bootstrapped via POST /api/v1/auth/fido2/bootstrap/options + /bootstrap/verify (enabled only while no passkey exists) — the login page offers this automatically on a fresh install.

With SecretSpec (recommended):

# secretspec.toml
[project]
name = "astral-key"
revision = "1.0"

[profiles.default]
JWT_SECRET = { description = "JWT signing key (256-bit hex)", required = true }
DATABASE_URL = { description = "SQLite DSN", required = false, default = "sqlite://./astral-key.db?mode=rwc" }
FIDO2_RP_NAME = { description = "Relying Party name", required = false, default = "Astral Key" }

[profiles.production]
JWT_SECRET = { providers = ["vault://http://vault:8200"] }
DATABASE_URL = { providers = ["vault://http://vault:8200"] }
secretspec run -- astral-key

Documentation

Document Description
docs/architecture.md Module layout and authentication flows
docs/api.md Full API reference with curl examples
docs/deployment.md Docker Compose, Nix, K8s, SecretSpec
docs/errors.md Error code reference
CONTRIBUTING.md How to build, test, and submit PRs

Related Projects

Project Comparison
Pocket-ID Passkey auth, own DB, no Web3, no NixOS module
Hanko Passkey + password, own DB, cloud-dependent
Casdoor OIDC/SAML/Web3, own DB, Go, heavy
Authelio FIDO2 only, no Web3, no NixOS
Keycloak Full-featured SSO, Java, heavy, no Web3

Astral Key is the only self-hostable auth service that combines **passkey-native

  • Web3 wallet + SQLite storage** in a single Rust binary.

License

MIT License — see LICENSE for details.

Copyright © Jeremy Kroeker (reverb256)

About

Astral Key + Mosaic Identity Foundation: Rust auth sidecar (FIDO2/Web3), MIS PKI, and 9 federation bridges

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages