- Rust 77.7%
- TypeScript 11.4%
- Shell 8.5%
- Python 1.5%
- Makefile 0.6%
- Other 0.3%
Ahdapa
Stateless OAuth 2.0 / OpenID Connect identity provider (IdP) written in Rust, designed for FreeIPA-managed Kerberos environments. The name comes from the Adapa, a Mesopotamian mythical figure who unknowingly refused the gift of immortality.
What it does
- OAuth 2.0 (RFC 6749) — authorization code, refresh token, client credentials, device authorization, and token exchange grant types.
- OpenID Connect Core 1.0 — ID tokens, UserInfo endpoint, pairwise subjects, OIDC Discovery.
- SPNEGO/Kerberos SSO — zero-click authentication for domain members via GSSAPI; password form backed by FreeIPA LDAP as fallback.
- Stateless tokens — self-contained JWTs; authorization codes and refresh tokens are AES-256-GCM encrypted. No per-token server-side storage. Explicit logout records a short-lived session revocation so the invalidated session cookie is rejected immediately.
- Horizontal scale — signing keys and client registry replicated across nodes with a built-in CRDT gossip protocol; any node handles any request.
- Post-quantum ready — ML-DSA-44/65/87 signing alongside classical EdDSA/ES256/RS256.
- Self-service profile editing — authenticated users can view and modify their own IPA
attributes (name, contact, SSH keys, certificates, password) through the
/ui/mepage. Editability is driven by IPAattributelevelrightsand admin-configurable visibility rules. - Federation — upstream IdP delegation (§6) with
client_secret_post/basicandprivate_key_jwt; supports OIDC Discovery and static endpoint overrides for plain OAuth2 providers (GitHub, Discord, etc.). - RBAC — group-based permissions on the admin API; groups sourced from a static users file
or FreeIPA LDAP
memberOf. - Identity HBAC policy — FreeIPA-compatible Handler-Based Access Control enforced at token
issuance. Policies control which users (Identity Subjects) may obtain tokens from which OAuth2
clients (Identity Handlers) for which scopes (Scoped Access). Rules are an op-based CRDT
(
hbac-crdt) replicated via gossip. Empty rule set = allow-all (backward compatible);client_credentialsgrant is exempt. - SPIFFE Workload API — optional SPIFFE trust domain authority and Workload API server.
When
[spiffe] trust_domainis configured, ahdapa issues X.509-SVIDs and JWT-SVIDs to local workloads via a Unix domain socket gRPC server, publishes the trust bundle at/.well-known/spiffe-bundle, and bridges SPIFFE identity to OAuth2 tokens. - ACME Token Authority (RFC 9447) — when
[gssapi]is configured, ahdapa issues authority tokens for ACMEtkauth-01challenges atPOST /at/account/{id}/token. Authentication is via Kerberos SPNEGO; the resulting authority token JWT carriesEnhancedJWTClaimConstraints(RFC 9118) withmustInclude: ["sub"]andpermittedValuesbindingsubto the Kerberos principal,issto the issuer URL, and (for host/service principals)dnsto IPA-managed FQDNs — a Kerberos-identity binding, not the telephonytnauthlistprofile.
Standards
| RFC / Spec | Description |
|---|---|
| RFC 6749 | OAuth 2.0 Authorization Framework |
| RFC 6750 | Bearer Token Usage |
| RFC 7009 | Token Revocation |
| RFC 7519 | JSON Web Token (JWT) |
| RFC 7521 / 7523 | JWT Bearer Assertion + Client Authentication |
| RFC 7636 | PKCE (S256) |
| RFC 7662 | Token Introspection |
| RFC 8414 | Authorization Server Metadata |
| RFC 8628 | Device Authorization Grant |
| RFC 8693 | Token Exchange |
| RFC 8707 | Resource Indicators |
| RFC 9068 | JWT Profile for Access Tokens |
| RFC 9126 | Pushed Authorization Requests (PAR) |
| RFC 9207 | Authorization Server Issuer Identification |
| RFC 8705 | Mutual-TLS Client Authentication |
| RFC 9449 | DPoP |
| RFC 9700 | OAuth 2.0 Security Best Current Practice |
| RFC 8226 / RFC 9118 | JWTClaimConstraints / EnhancedJWTClaimConstraints — used as the Kerberos-identity constraint format in authority tokens |
| RFC 9447 | ACME Token Authority (tkauth-01) — Kerberos-authenticated issuance only |
| OIDC Core 1.0 | OpenID Connect Core |
| OIDC Discovery 1.0 | OpenID Connect Discovery |
| OIDC Federation 1.0 | Entity Statement (self-signed); bilateral trust |
Prerequisites
- Rust 1.80+ (
rustup) - OpenSSL 3.x development headers
- MIT Kerberos development libraries
- OpenLDAP client development libraries
- Node.js 20+ and npm (WebUI only)
Fedora / RHEL:
sudo dnf install openssl-devel krb5-devel openldap-devel
For --features pam: sudo dnf install pam-devel
Debian / Ubuntu:
sudo apt install libssl-dev libkrb5-dev libldap-dev
For --features pam: sudo apt install libpam0g-dev
Building
cargo build --release # server binary → target/release/ahdapa
cd webui && npm install && npm run build # WebUI → webui/dist/
Quick start
# /etc/ahdapa/config.toml
[server]
issuer = "https://idp.example.com"
realm = "EXAMPLE.COM"
[db]
url = "sqlite:///var/lib/ahdapa/ahdapa.db"
[gssapi]
service = "HTTP"
keytab = "/etc/ahdapa/ahdapa.keytab"
[ipa]
uri = "ldaps://ipa.example.com"
[webui]
static_dir = "/usr/share/ahdapa/webui"
# Without [rbac], the admin API is inaccessible.
[[rbac.role]]
name = "admin"
permissions = ["*"]
[[rbac.group_role]]
group = "admins"
role = "admin"
AHDAPA_CONFIG=/etc/ahdapa/config.toml ./target/release/ahdapa
See docs/src/quickstart/ for a full walkthrough including database initialization and
systemd unit setup.
Database backends
Select a backend at compile time via Cargo features (default: SQLite):
| Backend | Feature flag | Connection URL prefix |
|---|---|---|
| SQLite | backend-sqlite (default) |
sqlite:///path/to/file.db |
| PostgreSQL | backend-postgres |
postgres://user:pass@host/db |
| MariaDB / MySQL | backend-mariadb |
mariadb://user:pass@host/db |
cargo build --release --no-default-features --features backend-postgres
Optional features
| Feature | Default | Description |
|---|---|---|
backend-sqlite |
yes | SQLite database backend. |
backend-postgres |
no | PostgreSQL database backend. |
backend-mariadb |
no | MariaDB / MySQL database backend. |
varlink |
no | Enable user/group attribute lookup via the systemd io.systemd.UserDatabase varlink interface ([varlink] config section). Requires systemd 246+. Password authentication is not performed through varlink. |
pam |
no | Enable PAM password authentication backend ([pam] config section). Inserts a PAM step between static-user lookup and LDAP simple bind. Supports expired-password change via /login/change-password. Requires pam-devel at build time. |
To enable varlink support alongside the default SQLite backend:
cargo build --release --features varlink
Repository layout
src/ Server binary (Rust)
auth/ Authentication: GSSAPI, LDAP, AEAD, cookies, RBAC, federation
routes/ Axum route handlers: OAuth2, admin API, federation, discovery, SPIFFE bundle
crdt/ CRDT types: LWW map, OR-map, grow-set, refresh families, SPIFFE entries
db/ sqlx pool setup and schema row types
workload.rs SPIFFE Workload API gRPC server (tonic, Unix domain socket)
crates/
ahdapa-gssapi/ GSSAPI/SPNEGO acceptor (Kerberos)
ahdapa-jose/ JOSE: JWK, JWS, JWT signing and verification (incl. ML-DSA)
ahdapa-ldap/ Async LDAP client for FreeIPA user and group lookup
ahdapa-varlink/ Varlink userdb client (systemd io.systemd.UserDatabase, optional)
ahdapa-pam/ PAM authentication backend (inline libpam FFI, optional)
ahdapa-spiffe/ SPIFFE CA, SVID issuance, trust bundle, Workload API stubs (tonic/prost)
hbac-crdt/ Identity HBAC policy engine: op-based CRDT, FreeIPA-compatible rule semantics, OAuth2 axes
webui/ React 19 + TypeScript + PatternFly 6 admin panel and login UI
migrations/ SQL migration scripts (sqlite/, postgres/, mariadb/)
contrib/
demo/ Local demo configurations and run scripts
cluster/ Three-node gossip cluster demo (see contrib/demo/cluster/README.md)
spiffe/ SPIFFE Workload API demo (see contrib/demo/spiffe/README.md)
ci/ local-ci.sh — runs build, fmt, clippy, tests, and docs
packages/ RPM packaging: ahdapa.spec.in, rust2rpm.toml, Makefile (make srpm / make copr-build)
systemd/ systemd unit, sysusers.d, and tmpfiles.d templates for the RPM
docs/ mdBook user and developer documentation
CI
contrib/ci/local-ci.sh all # build · fmt · clippy · test · docs
contrib/ci/local-ci.sh build test # specific jobs only
The CI script requires cargo, rustfmt, and clippy. mdbook is optional (docs build).
Documentation
Full configuration reference, architecture notes, and the developer guide are in docs/.
Build the book with mdbook build docs/ or browse docs/src/ as plain Markdown.
License
GPL-3.0-or-later — see LICENSE.