本文整合了多个常用应用集成 Authentik OAuth 认证的配置方法,包括 Airflow、Grafana 和 JupyterHub。

通用 Authentik 配置

在 Authentik 中创建 OAuth2/OpenID 应用时,需要配置以下端点:

端点 URL 格式
授权 https://authentik.example.com/application/o/authorize/
Token https://authentik.example.com/application/o/token/
UserInfo https://authentik.example.com/application/o/userinfo/
元数据 https://authentik.example.com/application/o/{app}/.well-known/openid-configuration

重要提示userinfo 端点的路径必须带斜杠 /userinfo/,否则会报错。


Airflow 集成

版本信息

  • App Version: 2.8.3
  • Chart Version: 1.13.1

OAuth 认证配置

webserver_config.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from flask_appbuilder.security.manager import AUTH_OAUTH
from airflow.auth.managers.fab.security_manager.override import FabAirflowSecurityManagerOverride

AUTH_TYPE = AUTH_OAUTH
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "User" # 默认角色

OAUTH_PROVIDERS = [
{
"name": "OAuth",
"icon": "fa-circle-o",
"token_key": "access_token",
"remote_app": {
"client_id": "your-client-id",
"api_base_url": "https://authentik.example.com/application/o/",
"client_secret": "your-client-secret",
"client_kwargs": {"scope": "openid email profile"},
"server_metadata_url": "https://authentik.example.com/application/o/oauth/.well-known/openid-configuration",
},
}
]

PERMANENT_SESSION_LIFETIME = 259200 # 3 天


class CustomSecurityManager(FabAirflowSecurityManagerOverride):
def get_oauth_user_info(self, provider, resp):
if provider != "OAuth":
return {}

# 关键:必须是 userinfo/ 而不是 userinfo
me = self.appbuilder.sm.oauth_remotes[provider].get("userinfo/")
data = me.json()

return {
"email": data["email"],
"username": data.get("name", ""),
"first_name": data.get("given_name", ""),
"role_keys": data.get("groups", []), # 支持组映射
}


SECURITY_MANAGER_CLASS = CustomSecurityManager

LDAP 认证配置(备选)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from flask_appbuilder.security.manager import AUTH_LDAP

AUTH_TYPE = AUTH_LDAP
AUTH_LDAP_SERVER = "ldap://ldap.example.com"
AUTH_LDAP_USE_TLS = False

AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Admin"

AUTH_LDAP_LASTNAME_FIELD = "cn"
AUTH_LDAP_EMAIL_FIELD = "mail"
AUTH_LDAP_SEARCH = "ou=foo,ou=People,dc=example,dc=com"
AUTH_LDAP_UID_FIELD = "uid"
AUTH_LDAP_BIND_USER = "cn=admin,dc=example,dc=com"
AUTH_LDAP_BIND_PASSWORD = "adminPassword"

AUTH_ROLES_MAPPING = {
"cn=g-admin,ou=Group,dc=example,dc=com": ["Admin"],
}

AUTH_LDAP_GROUP_FIELD = "memberOf"
AUTH_ROLES_SYNC_AT_LOGIN = True
PERMANENT_SESSION_LIFETIME = 86400

API 认证

1
2
3
config:
api:
auth_backends: "airflow.api.auth.backend.basic_auth"

Grafana 集成

OAuth 认证配置

grafana.ini:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
grafana:
grafana.ini:
auth:
oauth_allow_insecure_email_lookup: true

auth.generic_oauth:
enabled: true
name: "OAuth"
client_id: "your-client-id"
client_secret: "your-client-secret"
scopes: "openid email profile offline_access"
auth_url: "https://authentik.example.com/application/o/authorize/"
token_url: "https://authentik.example.com/application/o/token/"
api_url: "https://authentik.example.com/application/o/userinfo/"
use_pkce: true
use_refresh_token: true
allow_sign_up: false
allow_assign_grafana_admin: true
auto_login: true
skip_org_role_sync: true

server:
root_url: "https://grafana.example.com/" # 必须正确配置

关键配置说明

配置项 说明 注意事项
root_url Grafana 访问地址 必须与实际域名一致,否则会重定向失败
oauth_allow_insecure_email_lookup 邮箱查找 使用邮箱匹配用户时需设为 true
use_pkce PKCE 支持 增强安全性

LDAP 认证配置(备选)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
grafana:
ldap:
enabled: true
config: |
verbose_logging = true

[[servers]]
host = "ldap.example.com"
port = 389
use_ssl = false
bind_dn = "cn=admin,dc=example,dc=com"
bind_password = "examplePassword"
search_filter = "(uid=%s)"
search_base_dns = ["ou=foo,dc=example,dc=com"]

[servers.attributes]
name = "cn"
surname = "sn"
username = "uid"
email = "mail"

[[servers.group_mappings]]
group_dn = "cn=g-admin,ou=Group,dc=example,dc=com"
org_role = "Editor"

JupyterHub 集成

OAuth 认证配置

values.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
hub:
config:
Authenticator:
admin_users:
- "admin"
allow_all: true
auto_login: true

GenericOAuthenticator:
client_id: "your-client-id"
client_secret: "your-client-secret"
login_service: "OAuth"
authorize_url: "https://authentik.example.com/application/o/authorize/"
token_url: "https://authentik.example.com/application/o/token/"
userdata_url: "https://authentik.example.com/application/o/userinfo/"
oauth_callback_url: "https://jupyter.example.com/hub/oauth_callback"
scope:
- "openid"
- "email"
- "profile"
username_claim: "sub"

JupyterHub:
authenticator_class: "generic-oauth"
admin_access: true

配置说明

配置项 说明 可选值
allow_all 是否允许所有用户 true / false
username_claim 用户名字段 sub / email / preferred_username
oauth_callback_url 回调地址 必须在 Authentik 中配置

LDAP 认证配置(备选)

1
2
3
4
5
6
7
8
9
10
11
hub:
config:
LDAPAuthenticator:
server_address: "ldap.example.com"
use_ssl: true
bind_dn_template:
- "uid={username},ou=foo,ou=People,dc=example,dc=com"
escape_userdn: true

JupyterHub:
authenticator_class: "ldapauthenticator.LDAPAuthenticator"

OAuth vs LDAP 对比

特性 OAuth LDAP
配置复杂度 简单 中等
统一登录(SSO) ✅ 支持 ❌ 不支持
离线访问 ✅ Refresh Token ❌ 需在线验证
安全性 ✅ PKCE 增强 一般
适用场景 现代 SSO 架构 传统 LDAP 环境

常见问题

userinfo 路径问题

Authentik 的 userinfo 端点必须是 /userinfo/(带斜杠),否则会报错:

1
ERROR - OAUTH userinfo does not have username or email {}

重定向 URI 不匹配

Grafana 报错 redirect_uri_mismatch:确保 root_url 与实际访问域名一致。

回调地址配置

JupyterHub 的 oauth_callback_url 必须在 Authentik 应用的”重定向 URI”中添加。


参考文档