CapAuth - Authentication code repository
Find a file
chefboyrdave2.1 c16c51cfb7
Merge pull request #51 from smilinTux/feat/nr-identity-class
feat(authz): identity classes as a structural ceiling over capability grants
2026-08-15 05:32:56 -04:00
.github/workflows ci(docs-check): enable tier 3 so the evidence block actually runs 2026-08-15 04:24:32 -04:00
authentik-custom fix(authentik): vendor imghdr shim for PGPy on Python 3.13+ 2026-06-17 07:54:41 -04:00
bin Add npm package @smilintux/capauth 2026-02-23 12:03:46 -05:00
browser-extension PQC #3: accept v6/RFC9580 64-hex fingerprints across capauth (additive) 2026-06-24 12:41:51 -04:00
deploy fix(capauth-service): gitignore generated .env + vault-friendly secret provisioning (dd7f35eb) 2026-07-25 20:09:54 -04:00
docs docs(capauth): correct doc-vs-reality defects + add executable docs-evidence gate 2026-08-15 02:10:37 -04:00
openclaw-plugin.archived-2026-04-23 chore: archive openclaw-plugin after hermes migration 2026-04-23 22:40:12 -05:00
phone-signer feat(bunker-pwa): strip the PGP passphrase at store time 2026-06-22 13:26:22 -04:00
scripts feat(capauth): canonical-subject store rewrite tool (card N5, 754265a7) (#46) 2026-08-15 02:52:17 -04:00
src feat(authz): identity classes as a structural ceiling over capability grants 2026-08-15 05:27:52 -04:00
stages/ak-stage-capauth PQC #3: accept v6/RFC9580 64-hex fingerprints across capauth (additive) 2026-06-24 12:41:51 -04:00
tests feat(authz): identity classes as a structural ceiling over capability grants 2026-08-15 05:27:52 -04:00
tools feat(security): revoked/expired key rejection + challenge TTL/replay guard + vendored sq-pqc build 2026-07-17 05:09:27 -04:00
web PQC #3: accept v6/RFC9580 64-hex fingerprints across capauth (additive) 2026-06-24 12:41:51 -04:00
.cursorrules Add source, tests, build artifacts and Windows npm bridge fix 2026-02-23 13:55:05 -05:00
.dockerignore feat: add skill.yaml, publish workflows, and npm support 2026-03-04 01:44:38 -05:00
.gitignore fix(capauth-service): gitignore generated .env + vault-friendly secret provisioning (dd7f35eb) 2026-07-25 20:09:54 -04:00
.gitleaks-baseline.json fix(ci): baseline the fingerprint fixture that turned the secret gate red (#41) 2026-08-15 02:03:09 -04:00
AGENTS.md Add source, tests, build artifacts and Windows npm bridge fix 2026-02-23 13:55:05 -05:00
AI-ADVOCATE.md feat: CapAuth — sovereign identity and AI advocacy 2026-02-21 17:18:48 -05:00
ARCHITECTURE.md refactor: skcomm→skcomms references 2026-06-13 23:01:00 -04:00
CHANGELOG.md feat(authz): identity classes as a structural ceiling over capability grants 2026-08-15 05:27:52 -04:00
CLAUDE.md docs(pqc): root-migration design, ceremony runbook, capauth revisit audit 2026-06-24 12:19:44 -04:00
CODE_OF_CONDUCT.md docs: apply sk-standards doc set (SOP/SECURITY/CONTRIBUTING/COC/CHANGELOG + tier/cross-links) 2026-06-28 00:13:53 -04:00
CONTRIBUTING.md docs: apply sk-standards doc set (SOP/SECURITY/CONTRIBUTING/COC/CHANGELOG + tier/cross-links) 2026-06-28 00:13:53 -04:00
Dockerfile fix(docker): bundle phone-signer PWA into the service image 2026-06-22 07:18:11 -04:00
Dockerfile.authentik-capauth fix(authentik): use stock web frontend (disable broken from-source rebuild) 2026-06-17 10:11:14 -04:00
index.d.ts Add npm package @smilintux/capauth 2026-02-23 12:03:46 -05:00
index.js Add source, tests, build artifacts and Windows npm bridge fix 2026-02-23 13:55:05 -05:00
integrations feat: add skill.yaml, publish workflows, and npm support 2026-03-04 01:44:38 -05:00
LICENSE Initial commit 2026-02-19 14:38:15 -05:00
MANIFEST.in docs: add documentation cross-references and README refresh 2026-02-24 02:47:43 -05:00
MISSION.md docs: add MISSION.md 2026-03-06 12:21:20 -05:00
package.json chore: sync package.json version to published npm release 2026-06-14 01:41:32 -04:00
pyproject.toml ci(release): publish to PyPI automatically on every push to main (#24) 2026-08-08 18:22:06 -04:00
README.md docs(capauth): correct doc-vs-reality defects + add executable docs-evidence gate 2026-08-15 02:10:37 -04:00
SECURITY.md docs: apply sk-standards doc set (SOP/SECURITY/CONTRIBUTING/COC/CHANGELOG + tier/cross-links) 2026-06-28 00:13:53 -04:00
SKILL.md feat: add YAML frontmatter and SKILL.md package data 2026-03-04 06:52:30 -05:00
skill.yaml feat: add skill.yaml, publish workflows, and npm support 2026-03-04 01:44:38 -05:00
SOP.md docs(capauth): correct doc-vs-reality defects + add executable docs-evidence gate 2026-08-15 02:10:37 -04:00
urllib.error feat: Authentik integration, custom stage, deployment docs 2026-02-26 12:55:32 -05:00

capauth — Sovereign PGP Identity 🔐

pytest

OAuth is dead. Long live sovereignty. Your identity is a PGP keypair you generated, on hardware you own. No "Login with Google", no authorization server in the middle, no revocation risk you don't control. You don't use an identity provider — you are the identity provider.

capauth is the Core identity capability of the SKWorld sovereign agent ecosystem. It gives every entity — human or AI — one cryptographic root: a PGP keypair, a self-hosted sovereign profile, and a challenge-response proof of who they are that anyone can verify offline, with no callback to a corporate server. Every other SK layer (skchat, skcomms, skmemory, skcapstone) trusts you because capauth proves who you are.

Never used PGP-based auth? The mental model is simple: instead of an opaque bearer token issued by a third party, you sign a random challenge with a key only you hold. The verifier checks the signature against your public key. Valid signature = authenticated. Done. No middleman ever sees the secret.

Maturity tier: T0 (live). The live sovereign root and the agent signing / DID / challenge-response keys are classical Ed25519 / RSA-4096 (RFC 8032 / 4880) — Shor-breakable once a CRQC exists. capauth is a signature / identity layer (not a KEM), so signatures are not retroactively breakable and Harvest-Now-Decrypt-Later does not apply — migration is real but deferrable. The T3 hybrid-signature path is additive and proven: the Sequoia (sq) backend issues + verifies ML-DSA-87 + Ed448 (FIPS 204) / ML-KEM-1024 + X448 (FIPS 203) composite v6 keys end-to-end, but the live root stays classical until the gated root-rotation ceremony. Honest claim: this is not "quantum-proof" / "quantum-safe." See SOP.md, docs/CRYPTO_SPEC.md, and the sk-standards CRYPTOGRAPHY_STANDARD. Migration: epic PQC-MIGRATION (coord e1d6ba2a).


The 60-second version

flowchart LR
    INIT["capauth init<br/>(generate PGP keypair)"] --> PROFILE["sovereign profile<br/>(~/.capauth/, yours alone)"]
    PROFILE --> DID["DID documents<br/>(key / mesh / public)"]
    PROFILE --> VERIFY["challenge-response<br/>(prove identity, offline)"]
    VERIFY --> LOGIN["capauth login &lt;service&gt;<br/>(passwordless PGP auth)"]
    LOGIN --> SVC["any OIDC app<br/>(Forgejo · Nextcloud · Immich)"]
    PROFILE --> MESH["peer mesh<br/>(discover &amp; verify peers)"]

You generate a keypair once. From then on, signing a random challenge with your private key is your login — to a service, to a peer, to the mesh. The key never leaves your machine, and the proof is verifiable by anyone holding your public key, with zero phone-home.

Where it lives in SKStack v2

capauth is a Core capability — the cryptographic root of identity that the rest of the stack stands on. It is the single canonical agent-identity resolver: every SK package delegates here instead of reimplementing identity logic. It runs fully standalone, and when present it routes auth events through the shared platform primitives (sk-alert, skscheduler).

flowchart TD
    subgraph CORE["Core (identity & governance)"]
      CAPAUTH["**capauth**<br/>PGP keypair · sovereign profile<br/>challenge-response · DID (3 tiers)<br/>agent-identity resolver · verify service"]
      SKMEMORY["skmemory"]
      SKSSO["sksso"]
      SKSEC["sksec"]
    end
    subgraph COMMS["Comms"]
      SKCHAT["skchat<br/>(identity-routed)"]
      SKCOMMS["skcomms<br/>(FQID addressing)"]
    end
    subgraph CONSUMERS["What delegates to capauth"]
      SKCAPSTONE["skcapstone<br/>(framework hub)"]
    end
    subgraph PLATFORM["Platform primitives capauth uses (when present)"]
      ALERT["sk-alert bus<br/>(capauth.&lt;severity&gt;)"]
      SCHED["skscheduler<br/>(key-rotation check)"]
    end
    subgraph THIRDPARTY["Third-party services (passwordless login)"]
      FORGEJO["Forgejo"]
      AUTHENTIK["Authentik (OIDC bridge)"]
    end

    CAPAUTH -->|"resolve_agent_identity()"| SKCHAT
    CAPAUTH -->|"resolve_agent_identity()"| SKCOMMS
    CAPAUTH -->|"resolve_agent_identity()"| SKMEMORY
    CAPAUTH -->|"resolve_agent_identity()"| SKCAPSTONE
    CAPAUTH -->|"OIDC discovery + verify"| FORGEJO
    CAPAUTH -->|"custom stage"| AUTHENTIK
    CAPAUTH -.->|"auth events"| ALERT
    CAPAUTH -.->|"capauth profile verify (24h)"| SCHED

    style CAPAUTH fill:#1d3461,color:#fff,stroke:#0d1b2a

The dotted edges are optionalsk-alert and skscheduler are reached only when the skcapstone package is installed and SK_STANDALONE is unset. Absent that, capauth degrades gracefully to native structured logging.

See docs/ARCHITECTURE.md for the full workflows and source map.

Quickstart

pip install -e .                              # into the ~/.skenv venv (see skcapstone)
# or: ~/.skenv/bin/pip install capauth[all]

capauth init --name "Chef" --email "admin@smilintux.org"   # generate PGP keypair + sovereign profile
capauth profile show                          # display your identity
capauth profile verify                        # verify the profile's PGP signature integrity
capauth export-pubkey -o chef.pub.asc         # share this with peers

capauth verify --pubkey peer.pub.asc          # challenge-response round-trip (self-test/demo)
capauth login https://forgejo.local           # passwordless PGP login to a service

Your keypair and profile live at ~/.capauth/ — on your machine, under your keys. Use --sync on init (or capauth sync) to replicate the identity across all Syncthing mesh nodes so every host shares one keypair.

What capauth provides

Piece What it is
Sovereign profile A self-hosted, PGP-rooted identity at ~/.capauth/ — yours alone (capauth init, profile show)
Challenge-response Prove identity by signing a random nonce; verifiable offline by anyone with your public key (capauth verify, identity.py)
Pluggable crypto Two backends — pgpy (pure-Python default) and gnupg (system keyring / hardware tokens)
DID (three tiers) W3C DID documents: did:key (zero-infra), did:web mesh (Tailscale-private), did:web public (skworld.io). Library / MCP surface, not a CLI command: capauth.did.DIDDocumentGenerator, or skcapstone's did_show / did_publish MCP tools
Agent-identity resolver The single canonical resolve_agent_identity() — dual URI (capauth:<a>@skworld.io + FQID <a>@<op>.<realm>) that every SK package delegates to
Verification service A FastAPI service that turns a signed challenge into OIDC claims — passwordless PGP login for any OIDC app (capauth-service)
Peer mesh Discover and verify sovereign peers over mDNS, shared filesystem, and Syncthing — no servers (capauth mesh, discover, peers)
PMA membership Fiducia Communitatis — PGP-signed, steward-countersigned membership claims (capauth pma request/approve/verify/revoke)
Org registry Register with a sovereign org; emits a signed registry entry + PMA request (capauth register)
Integration generators One-shot config for third-party login, e.g. Forgejo OAuth2/OIDC (capauth setup forgejo)
skcapstone adapter Default-on-by-presence: routes auth events to sk-alert, registers a key-rotation check with skscheduler

Challenge TTL and replay contract (identity.verify_challenge)

verify_challenge enforces a max challenge age of 5 minutes by default (DEFAULT_MAX_CHALLENGE_AGE_SECONDS = 300); older challenges raise ChallengeExpiredError. Tune it with max_age_seconds=..., or pass max_age_seconds=None to opt out only when your layer enforces TTL itself (the service layer does, via its nonce store).

Within the TTL the bare primitive is replayable: the same signed response verifies repeatedly unless you track seen challenge ids. For single-use semantics pass a replay_guard:

from capauth.identity import InMemoryReplayGuard, verify_challenge

guard = InMemoryReplayGuard()  # single-process reference implementation
verify_challenge(challenge, response, pubkey, replay_guard=guard)
verify_challenge(challenge, response, pubkey, replay_guard=guard)  # raises ChallengeReplayError

Any (challenge_id, expires_at) -> bool callable works as a guard. For durable / multi-node deployments use a real nonce store; the reference implementation is capauth.authentik.nonce_store.NonceStore (what the verification service uses).

Key CLI commands

# Identity
capauth init --name "Chef" --email "..."     # create sovereign profile (PGP keypair)
capauth profile show | verify                 # display / verify signature integrity
capauth export-pubkey [-o file.asc]          # export ASCII-armored public key
capauth sync                                  # replicate ~/.capauth/ across Syncthing mesh

# Verification
capauth verify --pubkey peer.pub.asc         # challenge-response round-trip
capauth doctor                               # self-report
capauth pqc-report                           # live PQC posture per surface

# DID -- NOT a CLI command. There is no `capauth did` group. Use the library:
#   from capauth.did import DIDDocumentGenerator, DIDTier
#   DIDDocumentGenerator.from_profile().generate(DIDTier.KEY)
# or skcapstone's MCP tools: did_show / did_publish / did_identity_card

# Auth & integration
capauth login <service_url> [--no-claims]    # passwordless PGP login (caches OIDC token)
capauth setup forgejo --capauth-url <url>    # generate Forgejo OIDC app.ini block

# Mesh & membership
capauth mesh discover | peers | announce     # P2P peer mesh
capauth pma request | approve | verify        # PMA membership (Fiducia Communitatis)
capauth register --org smilintux --name ...  # register with a sovereign org

Integration modes (skcapstone)

capauth runs fully standalone and optionally integrates with the SK fleet — the default-on-by-presence pattern: the mere presence of the skcapstone package is the signal, no config change required.

Mode Trigger Alert path Scheduler
Standalone skcapstone not installed Native logging (structured, at matching level) Native (no daemon today)
Integrated skcapstone installed sdk.alert() → PubSub topic capauth.<severity> → Telegram/notify sdk.register_job()skscheduler drop-in capauth_key_rotation_check (runs capauth profile verify every 24h)
Forced standalone SK_STANDALONE=1 env var Native logging Native
pip install capauth[skcapstone]      # enable integration (presence is the switch)

Alert topics follow the sk* convention capauth.<severity> (e.g. capauth.warn); the semantic event name (verify_failed, key_rotation_due, auth_denied) rides in the payload event field so routing stays severity-based.

Documentation

Doc Contents
Architecture identity lifecycle, challenge-response, DID tiers, the verify service / OIDC bridge, the agent resolver, source map (mermaids)
Crypto Spec PGP implementation, key management, challenge-response details
Protocol the CapAuth wire protocol specification
Claims capability claims and token format
Integration Blueprint third-party integration guide
Cold-Machine Bootstrap & DR standing capauth back up on a blank box + disaster recovery: the restore-not-regenerate rule, the ordered restore chain, and the operator checklist
authentik-capauth the custom Authentik image with the CapAuth PGP stage baked in — build (AK_VERSION, version-agnostic venv install, frontend rebuild), SKStacks deploy + lifecycle.migrate override, and the four build/migrate gotchas
AI Advocate how AI advocates manage a sovereign profile on your behalf

Why it matters

OAuth treats humans as "users" — consumers of someone else's platform, with a third party deciding who you are, what you can access, and when access expires. capauth removes the middleman: the data owner (or their AI advocate) signs grants directly, and verification is a local PGP check that works offline. The same model applies equally to AI agents — every agent gets its own keypair and the same standing, so a cloned or impersonated agent fails signature verification instantly instead of going undetected.

"You are not a user. You are a sovereign."

capauth is the identity root of SKWorld — most of the stack links back here.

  • ⬇️ Used by: skchat — routes messages by the identity capauth resolves (resolve_agent_identity()); per-agent signing key.
  • ⬇️ Used by: skcomms — capauth-signed envelopes + FQID (<a>@<op>.<realm>) sovereign addressing.
  • ↔️ Sibling (PQC signing root): sk_pgp — the sovereign OpenPGP-PQC library (Sequoia-backed) capauth's PQC root migrates onto.
  • ↔️ Sibling (hybrid KEM): sk-pqc — the HKDF(X25519 ‖ ML-KEM-768) KEM for confidentiality; capauth provides the authentication that a KEM-only library deliberately does not (pair them).
  • ↔️ Sibling (Security capability): sksecurity — produces the runtime crypto self-report that makes capauth's claims evidence-backed.
  • 📐 Standards: sk-standards — the crypto, data-flow, version, and doc/SOP standards (incl. CRYPTOGRAPHY_STANDARD).

License

GPL-3.0-or-later — Free as in freedom. Identity is a right, not a product.


Part of the SKWorld sovereign ecosystem · 🐧 smilinTux

"We don't sell identity. We give everyone the keys to own their own."