System API
Overview​
The purpose of the System API is to allow authentication portals (authenticate plugin) deployes on different instances
to share state among themselves, perform authentication database synchronization, and distributes various revocation lists.
Additionally, the same API is used by gatekeepers running authorization policies (authorize plugin) to
perform API key and Basic authentication through a remote authentication portals. The gatekeepers also
get revocation list via the API to prevent unauthorized access if a user was disabled, but the user's tokens
are still valid.
Communication Encryption​
The messages sent and received via the API are encoded in platform-agnostic security tokens (PASETO).
All authentication portals and authorization policy gatekeepers encrypt their communication with the same key.
Specifically, v4.local specification is being used.
The format of the token:
v4.local.<payload>.<footer>
The System API keys must have an identifier (kid) associated with them.
The identifier gets embedded in the footer of the token.
Configuration​
The syntax to configure shared encryption key follows.
authentication portal <PORTAL_NAME> {
crypto key <KEY_ID> system <file:PATH/TO/security_system.key>
}
authorization policy <POLICY_NAME> {
crypto key <KEY_ID> system {file.PATH/TO/security_system.key}
with api key auth portal https://<PORTAL_BASE_URL>/auth realm <REALM_NAME>
with basic auth portal https://<PORTAL_BASE_URL>/auth realm <REALM_NAME>
}
Note the use of
{file.*}replacer. Caddy will read thesecurity_system.keyfile and extract the shared key.You can also store the key in an environment variable, e.g.
SYSTEM_API_SECRET, and then reference it via environment variable replacer{env.*}, e.g.crypto key <KEY_ID> system {env.SYSTEM_API_SECRET}
The following command generates the shared encryption key. The key is random 256-bit (32-byte) symmetric key.
The algorithm used is XChaCha20-Poly1305.
authdbctl system generate key --output-key-file ~/.config/caddy/security_system.key
The ~/.config/caddy/security_system.key contains Base64 encoded key:
f6db709dadd4258c51c99fe60ddbbedc1178dc2255a16cd5a675a9f638e16d36
Key ID Field​
The kid field is mandatory for System API messages. It helps identifying the sources
of the API requests and rotating keys.
Messages​
Basic Authentication​
To perform basic authentication for a user, the gatekeeper (authenticate plugin) sends a message with
the following payload:
{
"kind": "basic_auth",
"username": "<USERNAME>",
"password": "<PASSWORD>",
"realm": "<REALM_NAME>"
}
The receiving portal responds with the following message:
{
"id": "faaf870b-c350-4a2b-bef3-ebfd90ae3f86",
"kind": "auth_response",
"authenticated": true,
"user_data": {
"addr": "10.1.1.1",
"email": "jsmith@localhost.localdomain",
"name": "Smith, John",
"origin": "local",
"realm": "local",
"roles": [
"authp/user",
"dash"
],
"sub": "jsmith"
},
"timestamp": "2026-03-29T16:06:45.73201Z"
}
Now, let's test the same with authdbctl utility.
cat <<EOF > .tmp/basic_auth_message.json
{
"kind": "basic_auth_request",
"username": "jsmith",
"password": "My@Password123",
"realm": "local",
"address": "10.1.1.1"
}
EOF
authdbctl --debug system send message --encryption-key ~/.config/caddy/security_system.key --input-message-file .tmp/basic_auth_message.json --key-id j163xe
The key ID must match the one configured on the authentication portal.
The following above command emulates the work of a gatekeeper (authorize plugin) that received Basic authentication
credentials and need to authenticate the credentials with remove authentication portal.
API Key Authentication​
To perform API key authentication for a user, the gatekeeper (authenticate plugin) sends a message with
the following payload:
{
"kind": "api_key_auth_request",
"api_key": "<API_KEY>",
"realm": "<REALM_NAME>",
"address": "<SOURCE_ADDRESS>"
}
The receiving portal responds with the following message:
{
"id": "0b719a2c-0894-4157-ba83-4f5c0ca50ceb",
"kind": "auth_response",
"authenticated": true,
"user_data": {
"addr": "10.1.1.1",
"email": "jsmith@localhost.localdomain",
"name": "Smith, John",
"origin": "local",
"realm": "local",
"roles": [
"authp/user",
"dash"
],
"sub": "jsmith"
},
"timestamp": "2026-03-29T16:53:55.993986Z"
}
Now, let's test the same with authdbctl utility.
cat <<EOF > .tmp/api_key_auth_message.json
{
"kind": "api_key_auth_request",
"api_key": "Lpi1BhMmSIcRk96E7QBovuik2rww3PV5JfSkzSVGNmKlNNCjpKbe66750TrUHIgcl67OEeCz",
"realm": "local",
"address": "10.1.1.1"
}
EOF
authdbctl --debug system send message --encryption-key ~/.config/caddy/security_system.key --input-message-file .tmp/api_key_auth_message.json --key-id j163xe
Restricting Access​
You can use Caddy matchers to match /api/system in the URL path and allow
access to the path only from specific IP addresses or address ranges.
@system_api_blocked {
path *api/system*
not remote_ip 192.168.1.0/24 10.0.0.0/8
}
handle @system_api_blocked {
respond "Forbidden" 403
}