Authentik: Self-Hosted Identity Provider Setup Guide
Authentik is a powerful, open‑source identity provider (IdP) that lets you centralise authentication, authorisation, and user management for your cloud‑native stack. In this guide we’ll walk through every step needed to spin up a self‑hosted Authentik instance, configure it for common protocols, and integrate it with real‑world applications. By the end, you’ll have a production‑ready IdP that can handle SSO, MFA, and fine‑grained access control—all without relying on a third‑party service.
Why Choose Authentik?
Unlike many commercial IdPs, Authentik is fully open source, extensible, and designed to run on modest hardware. It supports OAuth2, OpenID Connect (OIDC), SAML 2.0, LDAP, and even SCIM for provisioning. This flexibility makes it a natural fit for developers who want to keep their authentication stack under their own control.
Another advantage is its modern UI built with Vue.js, which simplifies admin tasks like creating providers, mapping attributes, and reviewing audit logs. Plus, the built‑in policies engine lets you enforce conditional access based on groups, IP ranges, or device posture.
Prerequisites
Before diving in, make sure you have the following:
- A Linux server (Ubuntu 22.04 LTS or Debian 12 are recommended) with at least 2 GB RAM and 2 CPU cores.
- Docker Engine ≥ 20.10 and Docker Compose ≥ 2.0 installed.
- A domain name pointing to your server’s public IP (e.g., auth.example.com).
- Access to port 443 (HTTPS) and optionally port 80 for HTTP‑to‑HTTPS redirection.
If you prefer Kubernetes, you can swap the Docker Compose steps for a Helm chart later in the guide. For now, we’ll stick with Docker Compose because it’s the quickest way to get a sandbox up and running.
Step 1: Deploy Authentik with Docker Compose
Creating the Compose File
Start by creating a directory for your Authentik deployment and a docker-compose.yml file inside it. The following example uses the official Authentik images and sets up a PostgreSQL database for persistence.
# docker-compose.yml
version: "3.9"
services:
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: authentik
POSTGRES_USER: authentik
POSTGRES_PASSWORD: changeme # ⚠️ Replace with a strong password
volumes:
- db-data:/var/lib/postgresql/data
restart: unless-stopped
authentik-server:
image: ghcr.io/goauthentik/server:2024.2.2
depends_on:
- db
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: db
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: changeme # Same as above
AUTHENTIK_SECRET_KEY: # 32‑byte base64 string, generate with `openssl rand -base64 32`
ports:
- "9000:9000" # HTTP (optional, for local testing)
- "9443:9443" # HTTPS (recommended)
volumes:
- ./media:/media
- ./templates:/templates
restart: unless-stopped
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
db-data:
Make sure to replace changeme with a secure password and generate a 32‑byte secret key. You can do that with:
openssl rand -base64 32
Save the key in an environment variable or a .env file and reference it in the compose file for better security.
Launching the Stack
Run the following command to pull the images and start the containers:
docker compose up -d
Docker will download the Authentik server, PostgreSQL, and Redis images, then spin up the services in the background. Verify everything is healthy with:
docker compose ps
You should see all three containers listed as “Up”. If any container restarts repeatedly, check the logs with docker compose logs <service> for clues.
Step 2: Initial Configuration via CLI
Creating the First Superuser
Authentik ships with a management CLI that lets you bootstrap the system. Execute the CLI inside the running container to create an admin account:
docker exec -it <container_id_or_name> /bin/bash
authentik-manage createsuperuser
# Follow the prompts:
# Email: admin@example.com
# Password: (choose a strong password)
# First name, last name: optional
The CLI also generates a default configuration file at /etc/authentik/config.yml. You can edit this file later to tweak settings such as token lifetimes or email backends.
Enabling HTTPS
Running Authentik behind HTTPS is non‑negotiable for production. The easiest way is to terminate TLS at a reverse proxy like Nginx or Traefik. Below is a minimal Nginx config that forwards traffic to the Authentik server’s internal port 9000 and automatically redirects HTTP to HTTPS.
# /etc/nginx/sites-available/authentik.conf
server {
listen 80;
server_name auth.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name auth.example.com;
ssl_certificate /etc/letsencrypt/live/auth.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.example.com/privkey.pem;
location / {
proxy_pass http://localhost:9000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
After placing the file, enable it with ln -s, reload Nginx, and verify you can reach https://auth.example.com/if/flow/redirect/ (the default login page).
Pro tip: Use Certbot to obtain free Let's Encrypt certificates. Run certbot --nginx -d auth.example.com and let it handle renewal automatically.
Step 3: Adding Your First Provider (OIDC)
Why OIDC?
OpenID Connect is the modern, JSON‑based protocol that powers Google Sign‑In, GitHub OAuth, and many SaaS platforms. By exposing an OIDC provider, Authentik can act as the identity source for any OIDC‑aware application.
We’ll create a provider for a demo Flask app, but the same steps apply to Kubernetes dashboards, Grafana, or any service that supports OIDC.
Creating the OIDC Provider in the UI
- Log in to the Authentik admin UI (usually
https://auth.example.com/if/admin/). - Navigate to Providers → OpenID Connect and click “Create”.
- Fill in the form:
- Name:
FlaskDemo - Redirect URIs:
http://localhost:5000/oidc/callback - Client ID: leave blank to auto‑generate.
- Client Secret: auto‑generated; copy it now.
- Name:
- Save the provider. The UI will display the
issuerURL (e.g.,https://auth.example.com/application/o/flaskdemo/).
Flask Application Example
Below is a minimal Flask app that uses Authlib to authenticate via the Authentik OIDC provider we just created.
# app.py
from flask import Flask, redirect, url_for, session, request
from authlib.integrations.flask_client import OAuth
app = Flask(__name__)
app.secret_key = 'replace-with-a-secure-random-secret'
oauth = OAuth(app)
authentik = oauth.register(
name='authentik',
client_id='YOUR_CLIENT_ID',
client_secret='YOUR_CLIENT_SECRET',
server_metadata_url='https://auth.example.com/application/o/flaskdemo/.well-known/openid-configuration',
client_kwargs={'scope': 'openid email profile'}
)
@app.route('/')
def index():
user = session.get('user')
if user:
return f"Hello, {user['email']}!"
return 'Login with Authentik'
@app.route('/login')
def login():
redirect_uri = url_for('auth_callback', _external=True)
return authentik.authorize_redirect(redirect_uri)
@app.route('/oidc/callback')
def auth_callback():
token = authentik.authorize_access_token()
user = authentik.parse_id_token(token)
session['user'] = user
return redirect('/')
if __name__ == '__main__':
app.run(debug=True, port=5000)
Replace YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with the values you copied from the Authentik UI. Run the app with python app.py and visit http://localhost:5000. Clicking “Login with Authentik” will redirect you to the Authentik login page, and upon successful authentication you’ll be back in Flask with the user’s email displayed.
Step 4: Configuring SAML 2.0 for Enterprise Apps
When to Use SAML
SAML remains the de‑facto standard for many legacy enterprise applications (e.g., Microsoft SharePoint, ServiceNow, or custom Java portals). Authentik’s SAML provider can act as an Identity Provider (IdP) that issues assertions to these Service Providers (SP).
Let’s set up a SAML provider for a generic SP that expects a NameID in email format and includes the groups attribute.
Creating the SAML Provider
- In the Authentik UI, go to Providers → SAML and click “Create”.
- Enter a descriptive name, e.g.,
EnterpriseSP. - Set Entity ID to your SP’s identifier (often a URL like
https://sp.example.com/metadata). - Upload the SP’s metadata XML file or paste the XML directly.
- Under “Attribute Mapping”, map
emailtoNameIDand add a custom attributegroupsthat pulls from the user’s group memberships. - Save the provider and note the IdP metadata URL (e.g.,
https://auth.example.com/application/saml2/enterprise-sp/metadata).
Testing with a SAML Test Tool
You can validate the configuration using SAMLTest.id. Register the IdP metadata URL, then initiate a login from the test portal. If everything is wired correctly, you’ll see a successful authentication with the expected attributes.
Pro tip: Enable Signed Assertions and Encrypted Assertions for production deployments. This protects user data in transit and satisfies compliance requirements like GDPR and HIPAA.
Step 5: Managing Users, Groups, and Policies
Importing Users via SCIM
SCIM (System for Cross‑Domain Identity Management) is ideal for bulk provisioning from HR systems or Azure AD. Authentik provides a built‑in SCIM endpoint that can be consumed by external tools.
To enable SCIM, create a “SCIM Provider” in the UI, assign it a token, and use the following endpoint format:
https://auth.example.com/scim/v2/
Then, from a Python script you can push users like this:
import requests, json
SCIM_TOKEN = 'your-scim-token'
HEADERS = {
'Authorization': f'Bearer {SCIM_TOKEN}',
'Content-Type': 'application/json'
}
USER_PAYLOAD = {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "jdoe",
"name": {"givenName": "John", "familyName": "Doe"},
"emails": [{"value": "jdoe@example.com", "primary": True}],
"active": True
}
resp = requests.post(
'https://auth.example.com/scim/v2/Users',
headers=HEADERS,
data=json.dumps(USER_PAYLOAD)
)
print(resp.status_code, resp.json())
The response will contain the newly created user’s ID, which you can later reference for group assignments or attribute updates.
Group‑Based Access Policies
Authentik’s policy engine lets you define rules that evaluate user attributes, groups, and request context. For example, you might want to restrict access to a “Finance Dashboard” to members of the finance group and only from corporate IP ranges.
- Create a group called
financeunder Groups → Create. - Navigate to Policies → Create and select “Expression Policy”.
- Enter an expression like:
user.is_in_group('finance') and request.ip in ['10.0.0.0/8'] - Attach this policy to the provider (e.g., the OIDC app) under “Access Policies”.
When a user attempts to authenticate, Authentik evaluates the expression. If the condition fails, the login is denied with a clear error message.
Step 6: Enabling Multi‑Factor Authentication (MFA)
Supported MFA Methods
Authentik supports TOTP (Google Authenticator, Authy), WebAuthn (FIDO2 security keys), and backup codes. Enabling MFA adds an extra layer of security, especially for admin accounts and privileged users.
To activate MFA globally, go to Settings → Authentication → MFA Settings** and toggle the “Require MFA for all users” switch. You can also enforce MFA per‑policy using the same expression language we saw earlier.
Configuring TOTP for a User
When a user logs in for the first time after MFA is required, Authentik will present a QR code. The user scans it with their authenticator app, which then generates time‑based codes. The user must also download a set of backup codes for recovery.
Pro tip: Encourage users to register a WebAuthn device (e.g., YubiKey) as a primary factor. WebAuthn is phishing‑resistant and provides a seamless login experience on modern browsers.
Step 7: Monitoring, Logging, and Backups
Collecting Logs with Loki
Authentik