Auth0 连接器

通过 Tajo 将 Auth0 连接到 Brevo,将已认证的用户档案同步为营销联系人,根据认证事件触发自动化,并以身份和访问管理洞察丰富您的客户数据。

概览

属性
平台Auth0(by Okta)
类别身份与访问(自定义)
设置复杂度中等
官方集成
同步数据用户、事件、角色、身份
认证方式机器对机器 OAuth 2.0

功能

  • 用户档案同步 - 将 Auth0 用户档案同步到 Brevo 联系人
  • 认证事件 - 在登录、注册和密码重置时触发自动化
  • 基于角色的细分 - 根据 Auth0 角色和权限细分联系人
  • 社交身份数据 - 用社交登录档案信息丰富联系人
  • 登录活动跟踪 - 跟踪最后登录、登录次数和设备数据
  • 多租户支持 - 跨多个 Auth0 租户同步用户

前提条件

开始之前,请确保您已具备:

  1. 具有 API 访问权限的 Auth0 账户
  2. 在 Auth0 中注册的机器对机器应用
  3. 授予 M2M 应用的管理 API 权限
  4. 具有 API 访问权限的 Brevo 账户
  5. 具有连接器权限的 Tajo 账户

认证

机器对机器 OAuth 2.0

Terminal window
# Create an M2M application in Auth0 Dashboard
export AUTH0_DOMAIN=your-tenant.auth0.com
export AUTH0_CLIENT_ID=your_client_id
export AUTH0_CLIENT_SECRET=your_client_secret
export AUTH0_AUDIENCE=https://your-tenant.auth0.com/api/v2/
// Get Management API access token
const tokenResponse = await fetch(
`https://${process.env.AUTH0_DOMAIN}/oauth/token`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: process.env.AUTH0_CLIENT_ID,
client_secret: process.env.AUTH0_CLIENT_SECRET,
audience: process.env.AUTH0_AUDIENCE,
grant_type: 'client_credentials'
})
}
);
const { access_token } = await tokenResponse.json();
// Token is valid for 24 hours by default

API 权限

仅向您的 M2M 应用授予所需范围:read:usersread:user_idp_tokensread:rolesread:logs。非必要不授予写入权限。

配置

基础设置

connectors:
auth0:
enabled: true
domain: "${AUTH0_DOMAIN}"
client_id: "${AUTH0_CLIENT_ID}"
client_secret: "${AUTH0_CLIENT_SECRET}"
audience: "https://${AUTH0_DOMAIN}/api/v2/"
sync:
users: true
events: true
roles: true
schedule: "0 */4 * * *" # Every 4 hours
lists:
all_users: 20
verified_users: 21
social_login: 22

字段映射

field_mapping:
email: email
given_name: FIRSTNAME
family_name: LASTNAME
nickname: NICKNAME
picture: AVATAR_URL
email_verified: EMAIL_VERIFIED
logins_count: LOGIN_COUNT
last_login: LAST_LOGIN_DATE
created_at: SIGNUP_DATE
user_metadata.phone: SMS
user_metadata.company: COMPANY
app_metadata.plan: SUBSCRIPTION_PLAN
app_metadata.role: USER_ROLE

API 端点

端点方法描述
https://{domain}/api/v2/usersGET列出或搜索用户
https://{domain}/api/v2/users/{id}GET获取用户
https://{domain}/api/v2/users/{id}PATCH更新用户元数据
https://{domain}/api/v2/users/{id}/rolesGET获取用户角色
https://{domain}/api/v2/rolesGET列出所有角色
https://{domain}/api/v2/logsGET获取日志事件
https://{domain}/api/v2/stats/active-usersGET获取活跃用户数
https://{domain}/api/v2/stats/dailyGET获取每日统计
https://{domain}/oauth/tokenPOST获取访问令牌

代码示例

初始化连接器

import { TajoClient } from '@tajo/sdk';
const tajo = new TajoClient({
apiKey: process.env.TAJO_API_KEY,
brevoApiKey: process.env.BREVO_API_KEY
});
await tajo.connectors.connect('auth0', {
domain: process.env.AUTH0_DOMAIN,
clientId: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET
});

将用户同步到 Brevo

// Paginate through Auth0 users
let page = 0;
const perPage = 50;
let hasMore = true;
while (hasMore) {
const response = await fetch(
`https://${domain}/api/v2/users?` +
new URLSearchParams({
page: page.toString(),
per_page: perPage.toString(),
include_totals: 'true',
search_engine: 'v3',
q: 'email_verified:true'
}),
{
headers: { 'Authorization': `Bearer ${accessToken}` }
}
);
const { users, total } = await response.json();
for (const user of users) {
await tajo.contacts.sync({
email: user.email,
attributes: {
FIRSTNAME: user.given_name,
LASTNAME: user.family_name,
LOGIN_COUNT: user.logins_count,
LAST_LOGIN_DATE: user.last_login,
SIGNUP_DATE: user.created_at,
EMAIL_VERIFIED: user.email_verified
},
listIds: [20]
});
}
page++;
hasMore = (page * perPage) < total;
}

通过日志流跟踪认证事件

// Set up Auth0 Log Stream webhook
// Configure in Auth0 Dashboard > Monitoring > Streams
app.post('/webhooks/auth0', async (req, res) => {
// Verify authorization header
const authHeader = req.headers.authorization;
if (authHeader !== `Bearer ${process.env.AUTH0_WEBHOOK_TOKEN}`) {
return res.status(401).send('Unauthorized');
}
const logs = req.body;
for (const log of logs) {
switch (log.data.type) {
case 's': // Successful login
await tajo.events.track({
email: log.data.details.email,
event: 'user_login',
properties: {
ip: log.data.ip,
user_agent: log.data.user_agent,
connection: log.data.connection
}
});
break;
case 'ss': // Successful signup
await tajo.contacts.sync({
email: log.data.details.email,
attributes: { SIGNUP_DATE: log.data.date },
listIds: [20]
});
break;
case 'sp': // Successful password change
await tajo.events.track({
email: log.data.details.email,
event: 'password_changed'
});
break;
}
}
res.status(200).send('OK');
});

基于角色的细分

// Sync user roles for segmentation
const rolesResponse = await fetch(
`https://${domain}/api/v2/users/${userId}/roles`,
{
headers: { 'Authorization': `Bearer ${accessToken}` }
}
);
const roles = await rolesResponse.json();
const roleNames = roles.map(r => r.name).join(', ');
await tajo.contacts.update(userEmail, {
attributes: {
USER_ROLE: roleNames,
IS_ADMIN: roles.some(r => r.name === 'admin')
}
});

速率限制

端点类别限制说明
管理 API50 请求/秒(免费)每租户
管理 API100 请求/秒(付费)每租户
认证 API因计划而异基于计划
日志流实时投递无速率限制
分页每页最多 50 条使用 pageper_page 参数

需要分页

Auth0 管理 API 每页最多返回 50 条结果。始终使用 pageper_page 参数实现分页。包含 include_totals=true 以获取总数。

故障排除

问题原因解决方案
401 Unauthorized令牌已过期请求新的 M2M 令牌(24 小时有效期)
403 Forbidden缺少范围向 M2M 应用授予所需权限
用户列表为空搜索查询错误使用 v3 引擎的 Lucene 查询语法
元数据缺失未设置元数据检查 user_metadata 和 app_metadata
速率限制 429请求过多使用重试头实现退避

调试模式

connectors:
auth0:
debug: true
log_level: verbose
log_sync: true

最佳实践

  1. 使用日志流 - 实时事件流而非轮询日志 API
  2. 实施分页 - 始终对大型租户的用户列表查询进行分页
  3. 缓存 M2M 令牌 - 在接近过期前复用令牌(默认 24 小时有效期)
  4. 使用搜索引擎 v3 - 使用 Lucene 查询语法高效搜索用户
  5. 仅同步已验证用户 - 过滤 email_verified:true 以避免未验证联系人
  6. 利用用户元数据 - 在 Auth0 user_metadata 中存储自定义属性以便同步

安全

  • 机器对机器 OAuth - 服务器到服务器认证的客户端凭据授权
  • 范围权限 - 授予最低所需管理 API 范围
  • 令牌轮换 - M2M 令牌默认 24 小时后过期
  • 日志流认证 - 使用 Bearer 令牌验证 Webhook 端点
  • 租户隔离 - 每个 Auth0 租户单独配置
  • 加密传输 - 所有 API 通信使用 TLS 1.2+

相关资源

Subscribe to updates

developer-docs

Drop your email or phone number — we'll send you what matters next.

auto-detect
AI 助手

你好!关于文档有任何问题都可以问我。