Authentik Operations¶
Operational guide for Authentik SSO configuration, email verification, and OIDC troubleshooting.
Quick Reference¶
| Property | Value |
|---|---|
| URL | https://auth.fzymgc.house |
| Admin UI | https://auth.fzymgc.house/if/admin/ |
| User Settings | https://auth.fzymgc.house/if/user/ |
| API Docs | https://api.goauthentik.io |
| OIDC Issuer (K8s) | https://auth.fzymgc.house/application/o/kubernetes/ |
| Kubernetes Client ID | kubernetes |
| Terraform Module | tf/authentik/ |
| Vault Secret Path | secret/fzymgc-house/cluster/authentik |
Architecture Overview¶
Email Verification Flow¶
Authentik does NOT have a native email_verified field. The email_verified claim must be stored in user.attributes.email_verified and read via a custom scope mapping.
+----------------------------------------------------------------+
| Email Verification Flow |
+----------------------------------------------------------------+
| New User Enrollment: |
| 1. User fills enrollment form (prompt stage) |
| 2. User account created inactive (write stage) |
| 3. Verification email sent (email stage) |
| 4. User clicks link, email verified |
| 5. Expression policy sets user.attributes.email_verified=true |
| 6. User logged in (login stage) |
+----------------------------------------------------------------+
| OIDC Token Generation: |
| 1. User authenticates |
| 2. Custom email scope reads user.attributes.email_verified |
| 3. JWT includes email_verified claim with actual value |
+----------------------------------------------------------------+
Key Terraform Resources¶
| Resource | File | Purpose |
|---|---|---|
authentik_property_mapping_provider_scope.email_verified |
data-sources.tf |
Custom email scope with email_verified from attributes |
authentik_flow.enrollment_with_email_verification |
enrollment-flow.tf |
Enrollment flow with email verification |
authentik_stage_email.enrollment_email_verification |
enrollment-flow.tf |
Email verification stage |
authentik_policy_expression.set_email_verified |
enrollment-flow.tf |
Sets email_verified: true after verification |
User Management¶
Create User¶
- Navigate to Admin UI > Directory > Users
- Click "Create" and fill in details
- Assign to appropriate groups
Disable User¶
- Find user in Admin UI
- Set "Is Active" to false
- User immediately loses access
Password Reset¶
Users can self-service via "Forgot Password" flow if email is configured.
Group Management¶
| Group | Access |
|---|---|
authentik Admins |
Full Authentik admin |
cluster-admins |
Kubernetes admin access |
vault-admins |
Vault admin access |
OIDC Applications¶
Configured applications using OIDC:
- Kubernetes API (cluster access)
- Vault
- Grafana
- Windmill
Common Operations¶
Setting email_verified for Existing Users¶
Warning: Direct attribute manipulation bypasses enrollment flows and should only be used for migrating existing users. New users should always go through the enrollment flow.
Existing users created before the email verification flow need manual attribute setting:
# Get Authentik token from Vault
export VAULT_ADDR=https://vault.fzymgc.house
AUTHENTIK_TOKEN=$(vault kv get -field=terraform_token secret/fzymgc-house/cluster/authentik)
# Find user ID
curl -s -H "Authorization: Bearer $AUTHENTIK_TOKEN" \
'https://auth.fzymgc.house/api/v3/core/users/?search=USERNAME' | jq '.results[0].pk'
# Set email_verified attribute (replace USER_ID)
curl -s -X PATCH \
-H "Authorization: Bearer $AUTHENTIK_TOKEN" \
-H "Content-Type: application/json" \
-d '{"attributes": {"email_verified": true}}' \
"https://auth.fzymgc.house/api/v3/core/users/USER_ID/"
Revoking User Consent¶
To force a user to re-consent to an application:
- Go to https://auth.fzymgc.house/if/user/#/settings
- Navigate to Consent section
- Select the application and click Delete
Debugging OIDC Flows¶
-
Check provider configuration:
terraform -chdir=tf/authentik state show authentik_provider_oauth2.kubernetes -
List scope mappings on provider:
terraform -chdir=tf/authentik state show authentik_provider_oauth2.kubernetes | grep -A20 property_mappings -
Verify scope mapping expression:
terraform -chdir=tf/authentik state show authentik_property_mapping_provider_scope.email_verified
Troubleshooting¶
OIDC Authentication Returns "Unauthorized"¶
Symptom: kubectl --context fzymgc-house-oidc get nodes returns Unauthorized
Diagnosis Steps:
-
Clear OIDC cache and re-authenticate:
rm -rf ~/.kube/cache/oidc-login/ kubectl --context fzymgc-house-oidc get nodes -
Decode the JWT to check claims:
jq -r '.id_token | split(".")[1]' ~/.kube/cache/oidc-login/* | \ python3 -c "import sys,json,base64; print(json.dumps(json.loads(base64.urlsafe_b64decode(sys.stdin.read().strip()+'==')),indent=2))" -
Check if
email_verifiedistruein the JWT
Common Causes:
| Cause | Solution |
|---|---|
email_verified: false in JWT |
User's attributes.email_verified not set - see "Setting email_verified for Existing Users" |
| Missing groups claim | Check user group membership in Authentik |
| Token expired | Clear cache and re-authenticate |
| SSO session caching old claims | Log out of Authentik completely, then re-authenticate |
email_verified Always False¶
Root Cause: Authentik's default email scope returns email_verified: false for security reasons (see GitHub issue #16205).
Solution: Use custom email scope that reads from user.attributes.email_verified:
# Custom scope expression (in data-sources.tf)
return {
"email": request.user.email,
"email_verified": request.user.attributes.get("email_verified", False),
}
Consent Screen Not Showing Email Scope¶
Symptom: OAuth consent only shows "General Profile Information", not email
Cause: Scope mappings without a description field are treated as "silent" scopes
Solution: Add description to the scope mapping:
resource "authentik_property_mapping_provider_scope" "email_verified" {
name = "Email (with verified attribute)"
scope_name = "email"
description = "Email Address" # Required for consent display
expression = "..."
}
Terraform Resets User Attributes¶
Symptom: email_verified attribute disappears after Terraform apply
Cause: User resources managed by Terraform without ignore_changes for attributes
Solution: Add attributes to lifecycle ignore_changes:
resource "authentik_user" "example" {
# ... user config ...
lifecycle {
prevent_destroy = true
ignore_changes = [password, attributes] # Don't reset flow-managed state
}
}
Login Failures¶
- Check user is active
- Verify group membership
- Review Authentik logs in Grafana
OIDC Issues¶
- Check application configuration
- Verify redirect URIs
- Test with Authentik built-in debug tools