This episode covers Authentik automation: the REST API at /api/v3, API tokens, blueprints as declarative configuration, and using the Python client and Terraform provider to create users, flows, and properties programmatically.

So far everything has been done through the UI — Authentik is indeed UI-first. But as the number of users grows or you need reproducibility, clicking one by one in the UI won't work. Episode 21 opens the door to full automation: REST API, API tokens, blueprints, the Python client, and the Terraform provider.
The analogy is the difference between assembling a server by hand once versus writing a playbook that can be reused a hundred times. The latter is what makes staging and production environments identical.
Authentik provides a complete REST API that its own UI also uses. The key points:
https://auth.example.com/api/v3/.core/users, core/groups, core/applications, core/providers, flows/instances, policies, and many more./api/v3/schema/swagger-ui/.The API is large; in practice you only touch a small part. Start with the frequently used ones: users, groups, and property mappings.
API authentication uses tokens:
Authorization header as Bearer.Store tokens like passwords: in a secret manager (for example OpenBao or Vault, which you may have learned in other series), not in code or a repository.
List users:
curl -s https://auth.example.com/api/v3/core/users/ \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" | jq .resultsCreate a new user:
curl -s -X POST https://auth.example.com/api/v3/core/users/ \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"username": "arman", "name": "Arman Dwi Pangestu", "email": "arman@example.com", "is_active": true}'Notice how the POST request carries Content-Type: application/json and a JSON body — this pattern is the same for all object creation in Authentik.
A blueprint is a YAML file describing Authentik objects — users, groups, flows, providers, property mappings, even brands — in a single document. It's the bridge between "clicking in the UI" and "code".
Two important states of a blueprint instance:
Rule of thumb: use managed for things that must be uniform across all environments (for example standard providers), and unlocked for objects that genuinely need manual editing.
version: 1
entries:
- model: authentik_core.user
identifiers:
username: arman
attrs:
name: Arman Dwi Pangestu
email: arman@example.com
is_active: true
- model: authentik_core.group
identifiers:
name: admins
attrs:
users:
- !find authentik_core.user
where:
- username: arman
- model: authentik_core.propertymapping
identifiers:
name: mapping-grup-ke-claim
attrs:
expression: |
return {
"groups": [group.name for group in user.ak_groups.all()],
}Note the !find expression: a blueprint looks up existing objects and references them, so the admins group references the arman user without needing to guess a UUID. This is what makes blueprints idempotent — safe to apply repeatedly.
The combination of API and blueprints opens up common automation patterns:
For logic more complex than curl, there's a Python client generated from the OpenAPI spec (available as authentik-client). The usage pattern is consistent: create a client, then call endpoint functions:
from authentik_client.client import AuthentikClient
from authentik_client.api.core import core_users_list
client = AuthentikClient(
base_url="https://auth.example.com",
token="token-api-kalian",
)
users = core_users_list.sync(client=client)
for user in users.results or []:
print(user.username)The import structure follows the OpenAPI generator and may differ between SDK versions; always check the documentation for the version you use.
For deployments already based on Terraform (or OpenTofu), there's the goauthentik/authentik provider:
terraform {
required_providers {
authentik = {
source = "goauthentik/authentik"
version = "~> 2025.1"
}
}
}
provider "authentik" {
url = "https://auth.example.com"
token = var.authentik_token
}
resource "authentik_user" "arman" {
username = "arman"
name = "Arman Dwi Pangestu"
email = "arman@example.com"
is_active = true
}With this provider, identity objects become part of your infrastructure state: versioned, reviewable via pull requests, and revertible.
Tip
Start automation with the single thing you do manually most often, for example user creation. Once that pattern is comfortable, expand to groups, property mappings, then flows. Automation should grow, not be done all at once.
Summary of episode 21:
/api/v3 REST API exposes the entire configuration; authentication uses API tokens as Bearer.In episode 22, we put all that activity to another use: events and auditing for inspecting, exporting, and integrating the authentication trail. See you there!