Skip to content

Configuring OAuth Authentik Clients

Overview

Follow these steps to configure an OAuth Client via Authentik.

Prerequisites

  1. You must be an admin on Authentik.

Step 1: Create an Application

  • Navigate to Applications in Authentik.
  • Create a new Application.
  • Each Application will create a corresponding Provider.
  • Choose OAuth2 as the Provider type.

Authorization Flow

  • Select: default-provider-authorization-explicit-consent (Authorize Application).
  • Make the client confidential.
  • Retrieve the Client ID and Client Secret (needed for integration).

Step 2: Configure JupyterHub (Example)

Below is a sample JupyterHub configuration using Authentik as the OAuth provider:

hub:
config:
OAuthenticator:
login_service: "Authentik" # This is what shows on JH UI
oauth_callback_url: "https://XYZ.nrp-nautilus.io/hub/oauth_callback" # This is inputted by user
authorize_url: "https://authentik.nrp-nautilus.io/application/o/authorize/" # This is provided by Authentik
token_url: "https://authentik.nrp-nautilus.io/application/o/token/" # This is provided by Authentik
userdata_url: "https://authentik.nrp-nautilus.io/application/o/userinfo/" # This is provided by Authentik
client_id: "XYZ" # This is provided by Authentik
client_secret: "XYZ" # This is provided by Authentik
username_claim: "email"
allow_all: "True"
JupyterHub:
admin_access: true
authenticator_class: oauthenticator.generic.GenericOAuthenticator

Step 3: Configure Bindings (Filters & Policies)

  • In Configure Bindings, define filtering rules (blacklists, whitelists, user scopes).
  • Authentik uses Expression Policies (Python-based) to control access.

ore details on Expression Policies: Authentik Docs

For now, finish creating the Application without attaching a policy. Next, you’ll create the policy and bind it.

Step 4: Create an Expression Policy

  • Navigate to Customization → Policies → Create → Expression Policy.
  • In the Expression field, enter your filtering logic.

Example:

# Allowed emails (bypass restrictions)
allowed_emails = ["[email protected]"]
# Whitelist/blacklist domains
whitelist_domains = ["example.edu", "example.com"]
blacklist_domains = ["bad-domain.com"]
banned_users = ["[email protected]"]
allowed_exceptions = ["[email protected]"]
# Normalize lists
whitelist_lower = [d.lower().strip() for d in whitelist_domains]
blacklist_lower = [d.lower().strip() for d in blacklist_domains]
banned_lower = [b.lower().strip() for b in banned_users]
allowed_lower = [a.lower().strip() for a in allowed_emails]
allowed_exceptions_lower = [e.lower().strip() for e in allowed_exceptions]
# User context
user = request.context.get("pending_user", request.user)
# Validate user
if not user or not user.email:
ak_message("Access denied: Invalid credentials")
return False
email = user.email.lower().strip()
username, domain = email.split("@")
# Access rules
if email in allowed_lower:
ak_message("Access granted")
return True
elif email in banned_lower:
ak_message("Account suspended - contact admins")
return False
elif whitelist_lower and domain not in whitelist_lower:
if email in allowed_exceptions_lower:
ak_message("Special access granted")
return True
ak_message(f"@{domain} not authorized")
return False
elif domain in blacklist_lower and email not in allowed_exceptions_lower:
ak_message(f"@{domain} blocked")
return False
ak_message("Access granted")
return True

Policy Logic Flow

[Start]
Allowed Email Check → Approved? ✅ → Allow
| → Not listed ❌ → Deny
Banned User Check → Blocked? ❌ → Deny
Domain Mode Check
├─ Whitelist Mode:
│ ├─ Domain Approved? ✅ → Allow
│ ├─ Exception User? ✅ → Allow
│ └─ Else ❌ → Deny
└─ Blacklist Mode:
├─ Domain Blocked?
│ ├─ Exception User? ✅ → Allow
│ └─ Else ❌ → Deny
└─ Default ✅ → Allow

Policy Rules Explanation

🔹 Allowed Emails Take Priority
If allowed_emails is not empty, only those emails will be allowed.

🔹 Banned Users Are Always Blocked
Regardless of other conditions.

🔹 Whitelist Mode vs Blacklist Mode

  • If whitelist_domains is defined, only those domains are allowed (except explicitly allowed exceptions).
  • If whitelist_domains is empty, the system defaults to blacklist mode, where blocked domains deny access unless overridden.

Step 5: Bind the Policy to Your Application

  • Go back to your Application.
  • Open Policy / Group / User Bindings.
  • Bind the Expression Policy you just created.
  • In the Application Overview, use the Test button to verify user access.