Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

First Run

1. Create directories

sudo mkdir -p /etc/ahdapa /var/lib/ahdapa
sudo chown ahdapa:ahdapa /etc/ahdapa /var/lib/ahdapa
sudo chmod 0750 /etc/ahdapa /var/lib/ahdapa

2. Write a minimal configuration file

Create /etc/ahdapa/ahdapa.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"

Replace idp.example.com, EXAMPLE.COM, and the IPA hostname with your actual values.

3. Register the service principal in FreeIPA

ipa service-add HTTP/idp.example.com@EXAMPLE.COM
ipa-getkeytab -s ipa.example.com -p HTTP/idp.example.com@EXAMPLE.COM \
    -k /etc/ahdapa/ahdapa.keytab

4. Start the server

ahdapa /etc/ahdapa/ahdapa.toml

Or via systemd:

sudo systemctl start ahdapa

On first run, the server:

  1. Opens (or creates) the database and runs migrations.
  2. Generates a fresh JWT signing key pair using the configured algorithm (default: ES256 / ECDSA P-256) and stores it in the cluster state database.
  3. Generates a 32-byte AES-256-GCM cluster wrapping key and stores it in the cluster state database.
  4. Acquires the GSSAPI server credential from the keytab.
  5. Binds on the address from server.listen in the config file (default 0.0.0.0:8080), overridden by AHDAPA_LISTEN if set.

You will see log output like:

INFO ahdapa: Ahdapa starting issuer=https://idp.example.com
INFO ahdapa: GSSAPI server credential acquired
INFO ahdapa: listening addr=0.0.0.0:8080

5. Verify the discovery document

curl https://idp.example.com/.well-known/openid-configuration | jq .

The response is a static JSON document cached for 24 hours. All endpoint URLs will use the configured issuer.

6. Configure RBAC and register an OAuth2 client

All admin API endpoints require RBAC to be configured. Without a [[rbac.role]] / [[rbac.group_role]] section the server returns 403 for every admin request — access is denied to everyone.

Add the following to your config.toml and map it to a group that your admin user belongs to (via the static users file or FreeIPA LDAP memberOf):

[[rbac.role]]
name        = "admin"
permissions = ["*"]

[[rbac.group_role]]
group = "admins"
role  = "admin"

See Configuration Reference — [rbac] for the full permission list and group resolution details.

Once RBAC is configured, use the admin API (requires an authenticated session — log in via the WebUI first):

# Obtain a session cookie by logging in via the browser at:
#   https://idp.example.com/ui/auth/login

# Then register a client:
curl -X POST https://idp.example.com/api/admin/clients \
  -H 'Content-Type: application/json' \
  --cookie 'session=<your-session-cookie>' \
  -d '{
    "client_name": "My Application",
    "redirect_uris": ["https://myapp.example.com/callback"],
    "scopes": ["openid", "profile", "email"],
    "token_endpoint_auth_method": "client_secret_basic",
    "client_secret": "changeme"
  }'

The response contains the generated client_id.

Changing the listen address

Set server.listen in the config file to bind on a non-default address:

[server]
issuer  = "https://idp.example.com"
realm   = "EXAMPLE.COM"
listen  = "127.0.0.1:9090"

For a Unix domain socket (useful when a local reverse proxy or application talks to ahdapa over the same host):

[server]
listen = "unix:/run/ahdapa/ahdapa.sock"

ahdapa removes a stale socket file from a previous run on startup. Note that TLS ([tls] enabled = true) cannot be combined with a Unix socket listener.

The AHDAPA_LISTEN environment variable overrides server.listen without editing the config file, which is convenient for systemd drop-in overrides or container deployments:

AHDAPA_LISTEN=127.0.0.1:9090 ahdapa

Systemd socket activation

ahdapa supports systemd socket activation. When the ahdapa.socket unit is enabled, systemd pre-creates the socket and passes it to ahdapa as an inherited file descriptor. ahdapa detects the passed socket automatically and uses it instead of binding its own.

Enable the socket unit alongside the service:

sudo systemctl enable --now ahdapa.socket
sudo systemctl start ahdapa.service

With socket activation, systemd can start ahdapa on-demand when the first connection arrives, and connections made while ahdapa is restarting are queued by the kernel rather than refused.

The socket address in ahdapa.socket (ListenStream=) must match server.listen in the config file, since ahdapa logs the configured address even when using the inherited socket. The server.listen and AHDAPA_LISTEN values are ignored when a socket is passed by systemd.