OwnAuth
OwnAuth is a Nostr-backed, FROSTR-enabled Okta replacement. It provides OIDC, SAML, and SCIM capabilities, multi-tenant isolation, strong MFA, and OS login agents.
Services: Go 1.22+
Web: SvelteKit + TailwindCSS
Data: Postgres + Redis
Secrets: Vault integration from day 1
See ARCHITECTURE.md
for detailed design and flows.
Getting Started (dev)
Phase 1: Repo scaffold and docs (this commit)
Phase 2: Crypto primitives in
libs/nostr
andlibs/frostr
Phase 3: Core services (idp, directory, policy, saml, scim, api, frostr-gw, audit)
Docker, Helm charts, and CI will be added as we progress through phases.
OIDC Quickstart (dev)
The Directory service exposes basic OIDC endpoints suitable for local testing:
Discovery:
/.well-known/openid-configuration
JWKS:
/.well-known/jwks.json
(uses a dev RSA key persisted toservices/directory/dev-oidc-key.pem
)Authorize:
/oauth2/authorize
Token:
/oauth2/token
UserInfo:
/oauth2/userinfo
Dev Login UI:
/login
(collects a subject email to continue the flow)Dev Clients management:
/oauth2/clients
(GET/POST/PUT/DELETE)
Two demo clients are seeded:
demo-public
(no secret, requires PKCE)demo-confidential
(secretsecret
)
Assuming the Directory service runs on http://localhost:8080
:
Public client with PKCE (S256)
Generate a verifier and challenge (example Bash):
VERIFIER="testverifier12345678901234567890"
CHALLENGE=$(printf "%s" "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')
Authorize (will redirect to /login):
open "http://localhost:8080/oauth2/authorize?response_type=code&client_id=demo-public&redirect_uri=http://localhost/cb&code_challenge=$CHALLENGE&code_challenge_method=S256&state=xyz"
In the browser login page, enter an email (e.g.,
alice@example.com
). You will be redirected to yourredirect_uri
with?code=...
.Exchange code for tokens:
curl -s -X POST http://localhost:8080/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d grant_type=authorization_code \
-d code=REPLACE_WITH_CODE \
-d redirect_uri=http://localhost/cb \
-d client_id=demo-public \
-d code_verifier=$VERIFIER | jq .
Confidential client (Basic auth, PKCE optional)
Start authorize (will redirect to /login):
open "http://localhost:8080/oauth2/authorize?response_type=code&client_id=demo-confidential&redirect_uri=http://localhost/cb&state=xyz"
Login in the browser, capture the
code
from the redirect.Token exchange (HTTP Basic client auth):
curl -s -X POST http://localhost:8080/oauth2/token \
-u demo-confidential:secret \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d grant_type=authorization_code \
-d code=REPLACE_WITH_CODE \
-d redirect_uri=http://localhost/cb | jq .
Verify ID token signature
Fetch JWKS: curl -s http://localhost:8080/.well-known/jwks.json | jq .
Use a JWT tool to verify the id_token
using the returned key (RS256). In production, keys should be managed by a KMS and rotated.
SCIM and SAML
SCIM Users/Groups:
/scim/v2/Users
,/scim/v2/Groups
(supports list, get, create, delete; groups also support PATCH for members, and GET/scim/v2/Groups/{id}/members
)SAML Metadata:
/saml/metadata
, ACS:/saml/acs
(skeleton).
FROSTR Demo Quickstart (simulated threshold)
Prereqs: run the dev stack with docker compose.
docker compose -f deploy/docker/docker-compose.dev.yaml up --build
Request a signature from frostr-gw
POST http://localhost:8086/frostr/sign
Body:
{
"tenant": "default",
"nonce": "abc-123",
"message": "<BASE64_MESSAGE_BYTES>",
"devices": ["dev-1", "dev-2", "dev-3"],
"threshold": 2
}
The gateway fans out sign-requests, waits briefly for partials, fills any missing with deterministic simulated partials, aggregates, and returns a simulated signature. Audit events are emitted.
Optional: submit a partial from a device (one-shot)
go run ./agents/device-sim \
-gw http://localhost:8086 \
-device dev-1 \
-nonce abc-123 \
-message <BASE64_MESSAGE_BYTES> \
-wait 300ms
Automatic listener mode (polls inbox and auto-responds)
Run one or more listeners to simulate multiple devices answering:
go run ./agents/device-sim -gw http://localhost:8086 -device dev-1 -listen -poll 500ms
go run ./agents/device-sim -gw http://localhost:8086 -device dev-2 -listen -poll 500ms
When you POST /frostr/sign
, each listener polls /frostr/inbox
and auto-submits a simulated partial to /frostr/partial
.
Endpoints involved (gateway):
POST /frostr/sign
– start a signing roundPOST /frostr/partial
– devices submit partialsGET /frostr/inbox?device=<id>
– polling inbox for device simulators
SDK helpers (device):
sdks/go/frostr/
–SimulatePartialResponse()
andPostPartial()
Notes:
This is a simulated threshold path to enable demos now; real FROST aggregation will replace simulated partials in a later phase.