Authentik
Already running Apache2? Use mod_auth_openidc instead
If Apache2 is your webserver, mod_auth_openidc is the recommended approach — it handles the OIDC flow natively without a separate OAuth2 Proxy container. See Apache2 with mod_auth_openidc.
This guide walks through configuring Authentik as the identity provider for Wavelog using OAuth2 Proxy as the authenticating reverse proxy.
Architecture
OAuth2 Proxy handles the OIDC flow with Authentik and forwards the JWT access token to Wavelog as an HTTP header. Wavelog verifies the token using Authentik's JWKS endpoint.
Step 1: Create an OAuth2 Provider
In the Authentik Admin Interface:
- Go to Applications → Providers → Create
- Select OAuth2/OpenID Provider
- Configure:
- Name:
wavelog - Authorization flow: select your default authorization flow
- Client type:
Confidential - Redirect URIs:
https://wavelog.example.org/oauth2/callback
- Name:
- Save
After saving, copy the Client ID and Client Secret from the provider detail page.
Step 2: Create an Application
- Go to Applications → Applications → Create
- Configure:
- Name:
Wavelog - Slug:
wavelog - Provider: select the OAuth2 Provider created in Step 1
- Name:
- Save
Step 3: Add the Callsign Claim
Authentik does not include custom user attributes in tokens by default. You need to store the callsign as a user attribute and create a Scope Mapping to include it in the JWT.
3a. Add a user attribute
- Go to Directory → Users → select a user → Edit
-
In the Attributes field (JSON editor), add:
-
Save
Note
Authentik stores custom attributes as a JSON blob. There is no dedicated form field for custom attributes in the admin UI — this is the standard Authentik behavior. The attribute is stored correctly and will appear in the JWT as configured in the Scope Mapping below.
3b. Create a Scope Mapping
- Go to Customization → Property Mappings → Create
- Select Scope Mapping
-
Configure:
- Name:
Wavelog Callsign - Scope name:
wavelog_callsign -
Expression:
- Name:
-
Save
Tip
Use the same approach to map other user attributes (e.g. locator) to JWT claims by creating additional Scope Mappings.
3c. Add the Scope Mapping to the provider
- Go back to your OAuth2 Provider (
Applications→Providers→ selectwavelog) - Edit → Advanced protocol settings → Scopes
- Add
Wavelog Callsignto the list - Save
Step 4: Configure OAuth2 Proxy
OAuth2 Proxy acts as the authenticating reverse proxy. It handles the OIDC login flow with Authentik and forwards the JWT access token to Wavelog.
Important
OAuth2 Proxy must protect only /index.php/header_auth/login. All other Wavelog paths must be passed through without requiring authentication.
Docker Compose
services:
oauth2-proxy:
container_name: oauth2-proxy
image: quay.io/oauth2-proxy/oauth2-proxy:latest
command: --config /oauth2-proxy.cfg
hostname: oauth2-proxy
volumes:
- "./oauth2-proxy.cfg:/oauth2-proxy.cfg"
restart: unless-stopped
networks:
- proxy-net
nginx:
container_name: nginx-proxy
image: nginx:alpine
volumes:
- "./nginx.conf:/etc/nginx/conf.d/default.conf:ro"
- "./ssl:/etc/nginx/ssl:ro"
ports:
- "80:80"
- "443:443"
depends_on:
- oauth2-proxy
restart: unless-stopped
networks:
- proxy-net
networks:
proxy-net:
driver: bridge
oauth2-proxy.cfg
For detailed explanations refer to OAuth2 Proxy's official documentation.
http_address = "0.0.0.0:4180"
cookie_secret = "your-random-cookie-secret" # see below how to generate
provider = "oidc"
email_domains = ["*"]
client_id = "your-client-id"
client_secret = "your-client-secret"
redirect_url = "https://wavelog.example.org/oauth2/callback"
oidc_issuer_url = "https://authentik.example.org/application/o/wavelog/"
scope = "openid email profile wavelog_callsign"
insecure_oidc_allow_unverified_email = true
code_challenge_method = "S256"
pass_user_headers = true
set_xauthrequest = true
pass_access_token = true
# See https://oauth2-proxy.github.io/oauth2-proxy/configuration/session_storage
cookie_refresh = "4m"
cookie_expire = "30m"
skip_provider_button = true
whitelist_domains = "authentik.example.org"
Generate a cookie secret with:
Key differences from Keycloak
provider = "oidc"instead ofkeycloak-oidc— Authentik uses the generic OIDC providerscopemust explicitly includewavelog_callsignto request the custom scopeinsecure_oidc_allow_unverified_email = trueis required because Authentik does not mark user emails as verified by default. To remove this setting, go to Directory → Users, edit the user and enable Email verified manually.oidc_issuer_urlfollows the Authentik pattern:https://<authentik-domain>/application/o/<application-slug>/
Step 5: Configure Your Webserver
nginx
server {
listen 80;
server_name wavelog.example.org;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name wavelog.example.org;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.key;
# oauth2-proxy endpoints — OIDC flow (callback, sign-in, etc.)
location /oauth2/ {
proxy_pass http://oauth2-proxy:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Auth-Request-Redirect $request_uri;
# Recommended buffer settings for larger JWTs to prevent 502 errors
proxy_buffer_size 16k;
proxy_buffers 4 16k;
proxy_busy_buffers_size 16k;
}
# Auth subrequest endpoint (internal, used by auth_request only)
location = /oauth2/auth {
proxy_pass http://oauth2-proxy:4180;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_buffer_size 16k;
proxy_buffers 4 16k;
proxy_busy_buffers_size 16k;
}
# SSO login endpoint — oauth2-proxy authenticates, JWT is forwarded to Wavelog
location ^~ /index.php/header_auth/ {
auth_request /oauth2/auth;
# Not authenticated → start Authentik login directly (no splash screen)
error_page 401 = @sso_start;
# Forward JWT access token from oauth2-proxy to Wavelog
auth_request_set $access_token $upstream_http_x_auth_request_access_token;
proxy_set_header X-Authentik-Jwt $access_token;
proxy_pass http://wavelog:80;
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;
}
# Trigger Authentik login flow
location @sso_start {
return 302 /oauth2/start?rd=/index.php/header_auth/login;
}
# All other routes — no authentication required, Wavelog manages sessions itself
location / {
proxy_pass http://wavelog:80;
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;
}
}
Important
The header forwarded to Wavelog is X-Authentik-Jwt (not X-Forwarded-Access-Token as used with Keycloak). This must match auth_header_accesstoken in sso.php (see Step 6).
Step 6: Configure Wavelog
application/config/config.php:
application/config/sso.php (copy from sso.sample.php):
<?php
$config['auth_header_create'] = true;
$config['auth_header_allow_direct_login'] = false;
$config['auth_header_hide_password_field'] = true;
// Authentik JWT is forwarded by nginx as X-Authentik-Jwt
$config['auth_header_accesstoken'] = "HTTP_X_AUTHENTIK_JWT";
$config['auth_header_text'] = "Login with SSO";
// Redirect to Authentik end-session on logout
$config['auth_header_url_logout'] = 'https://authentik.example.org/application/o/wavelog/end-session/';
// Authentik JWKS endpoint — enables cryptographic JWT verification
$config['auth_header_jwks_uri'] = 'https://authentik.example.org/application/o/wavelog/jwks/';
$config['auth_headers_claim_config'] = [
'user_name' => [
'claim' => 'preferred_username',
'override_on_update' => true,
'allow_manual_change' => false,
],
'user_email' => [
'claim' => 'email',
'override_on_update' => true,
'allow_manual_change' => false,
],
'user_callsign' => [
'claim' => 'callsign',
'override_on_update' => true,
'allow_manual_change' => false,
],
'user_locator' => [
'claim' => 'locator',
'override_on_update' => true,
'allow_manual_change' => true,
],
'user_firstname' => [
'claim' => 'given_name',
'override_on_update' => true,
'allow_manual_change' => true,
],
'user_lastname' => [
'claim' => 'family_name',
'override_on_update' => true,
'allow_manual_change' => true,
],
];
Replace authentik.example.org and wavelog (the application slug) with your actual values.
Step 7: Verify
- Open Wavelog in the browser — the SSO login button should appear
- Click the button and complete the Authentik login
- You should be redirected to the Wavelog dashboard
If something is not working, enable debug logging in sso.php and config.php to inspect the JWT claims:
<?php
// sso.php
$config['auth_header_debug_jwt'] = true;
// config.php
$config['log_threshold'] = 2;
Check application/logs/log-YYYY-MM-DD.php for the decoded JWT payload. Verify that callsign, email and preferred_username are present and match your claim map.
Warning
Disable auth_header_debug_jwt again after troubleshooting.
Troubleshooting
email in id_token isn't verified
: Authentik does not mark emails as verified by default. Either add insecure_oidc_allow_unverified_email = true to oauth2-proxy.cfg (already included in the example above), or go to Directory → Users, edit the user and enable Email verified.
callsign claim missing from JWT
: The wavelog_callsign scope was not included in the token. Verify that:
- The Scope Mapping
Wavelog Callsignexists under Customization → Property Mappings - The scope is assigned to the provider under Advanced protocol settings → Scopes
scopeinoauth2-proxy.cfgexplicitly includeswavelog_callsign- The user has a
callsignattribute set under Directory → Users → Attributes
SSO Authentication: Missing access token header
: nginx is not forwarding the token header. Verify that:
auth_request_set $access_token $upstream_http_x_auth_request_access_token;is present in the/index.php/header_auth/blockproxy_set_header X-Authentik-Jwt $access_token;is set in the same blockauth_header_accesstoken = "HTTP_X_AUTHENTIK_JWT"is set insso.php