Authentik is one of the most widely deployed self-hosted identity providers and SSO solutions, protecting access to dozens of downstream services — making it an exceptionally high-value security target where a single compromise gives access to every application Authentik gates. Its security assessment covers: Authentik generates a random admin password on first startup that is printed to Docker logs and displayed in the initial setup wizard at /if/flow/initial-setup/ — this password is frequently not changed after setup; Authentik's API at /api/v3/ uses token-based authentication — admin tokens generated in Settings > Tokens grant full identity provider management including user creation, group assignment, and flow modification; Authentik's LDAP outpost stores a service account bind credential used by downstream services to authenticate against Authentik's LDAP interface — this bind password is stored in the outpost configuration; Authentik's authentication flows are composed of policy-bound stages — a stage whose policy evaluates to False is supposed to be skipped, but expression policy logic errors can result in unintended stage skipping that bypasses MFA or email verification; and Authentik's embedded outpost exposes a separate proxy authentication endpoint whose outpost tokens are sensitive. This guide covers systematic Authentik security assessment.
# Authentik initial setup — generated admin password in Docker logs
# Extract the default admin password from container logs
docker logs authentik-server 2>&1 | grep -i "default admin\|generated password\|akadmin" | head -5
# Or check the worker container
docker logs authentik-worker 2>&1 | grep -i "password\|akadmin" | head -5
# Test initial setup page accessibility
AUTHENTIK_URL="https://sso.example.com"
SETUP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
"${AUTHENTIK_URL}/if/flow/initial-setup/" 2>/dev/null)
echo "Initial setup flow status: ${SETUP_STATUS}"
# With valid admin credentials — get API token
curl -s -X POST "${AUTHENTIK_URL}/api/v3/core/tokens/" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"identifier":"audit-token","intent":"api","expiring":false}' 2>/dev/null
# Enumerate all users via API
curl -s "${AUTHENTIK_URL}/api/v3/core/users/?page_size=100" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Users: {d.get(\"count\")}')
for u in d.get('results',[])[:10]:
print(f' {u.get(\"username\")} ({u.get(\"email\",\"?\")}) is_superuser={u.get(\"is_superuser\")}')
" 2>/dev/null
# Authentik LDAP outpost — stores service account bind credentials
# Used by downstream services (Nextcloud, Gitea, etc.) to authenticate users via LDAP
AUTHENTIK_URL="https://sso.example.com"
ADMIN_TOKEN="your-authentik-admin-token"
# List all outposts and their configuration (includes LDAP bind tokens)
curl -s "${AUTHENTIK_URL}/api/v3/outposts/instances/" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for op in d.get('results',[]):
print(f'Outpost: {op.get(\"name\")} type={op.get(\"type\")}')
config = op.get('config',{})
token = op.get('token_identifier','')
print(f' Token identifier: {token}')
# The service account token used by LDAP clients is the outpost token
" 2>/dev/null
# Get the LDAP service account token (used as LDAP bind password by clients)
curl -s "${AUTHENTIK_URL}/api/v3/core/tokens/?identifier=authentik-outpost-" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for t in d.get('results',[]):
if 'outpost' in t.get('identifier','').lower():
print(f'Outpost token: {t.get(\"identifier\")} key={t.get(\"key\",\"[hidden]\")}')
" 2>/dev/null
docker logs authentik-server | grep password and change it immediately in the admin panel; do not leave the generated password active after initial setupFalse skip the bound stage — verify that MFA and email verification stages cannot be bypassed by submitting flow steps out of order or with manipulated policy evaluation| Security Test | Method | Risk |
|---|---|---|
| Default generated admin password unchanged | docker logs authentik-server grep password; test at /if/flow/initial-setup/ — unchanged generated password gives full Authentik admin access, controlling all downstream SSO-protected services | Critical |
| Admin API token extraction | GET /api/v3/core/tokens/ with admin credentials — lists all API tokens; admin tokens grant full identity provider management including user creation and group manipulation across all SSO-protected applications | Critical |
| LDAP outpost bind credential exposure | GET /api/v3/outposts/instances/ — outpost service account token used as LDAP bind password by all downstream LDAP-integrated services; exposure enables authentication as any user against all LDAP-integrated services | Critical |
| Authentication flow policy bypass | Submit flow steps out of order or test expression policy evaluation — MFA stage binding policies with logic errors may evaluate to skip=True, bypassing multi-factor authentication for all users of that flow | High |
| All users enumerable via API | GET /api/v3/core/users/ with admin token — lists all user accounts across all SSO-integrated applications with email, username, and group membership | High |
| OAuth/OIDC client secrets in application config | GET /api/v3/providers/oauth2/ — OAuth 2.0 provider client secrets stored in Authentik; exposure allows forging OAuth flows to authenticate to any Authentik-protected application | High |
Ironimo tests Authentik deployments for unchanged generated admin passwords (extracted from Docker logs), API token enumeration granting full identity provider management, LDAP outpost service account token exposure enabling authentication as any user against LDAP-integrated services, authentication flow policy bypass testing for MFA stage skipping, full user account enumeration via the API, and OAuth/OIDC client secret extraction from application provider configurations.
Start free scan