关于 auth0-laravel-api
使用 auth0/login 验证 Auth0 访问令牌、保护 Laravel API 端点的 Agent 技能。它指导配置无状态 API 守卫,并检查 JWT 声明、权限范围和权限。
主要功能
- 01配置 Auth0 API 守卫
- 02验证 JWT 访问令牌
- 03检查权限范围与权限
- 04在 Laravel 中读取令牌声明
- 05设置受保护的 API 路由
适用场景
- 01使用 Auth0 保护 Laravel API 端点
- 02按令牌权限范围限制路由
- 03检查 API 请求中的权限
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ auth0/ agent-skills --skill auth0-laravel-api安装后在 Claude Code 中输入/auth0-laravel-api确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api.mdintegration.mdsetup.md详细介绍
Auth0 Laravel API 集成
使用 auth0/login 和 AuthorizationGuard 验证 JWT 访问令牌,以保护 Laravel API 端点。
前置条件
- Laravel 11+ 应用
- PHP 8.2+,并包含扩展:
mbstring、openssl、json - 已安装 Composer
- 已配置 Auth0 API 资源(必须是 API,而非 Application)
- 如果尚未设置 Auth0,请先使用
auth0-quickstartskill
不适用场景
| 场景 | 请改用 |
|---|---|
| 带有登录/注销界面的 Laravel Web 应用 | auth0-laravel(基于会话的 AuthenticationGuard) |
| 纯 PHP API(无框架) | auth0-php-api |
| 纯 PHP Web 应用 | auth0-php |
| 单页应用 | auth0-react、auth0-vue 或 auth0-angular |
| FastAPI / Python API | auth0-fastapi-api |
| Express / Node.js API | express-oauth2-jwt-bearer |
| 签发令牌 | 此 skill 用于验证访问令牌,而非签发令牌 |
快速入门工作流
1. 安装 SDK
composer require auth0/login
auth0/login 包需要 auth0/auth0-php(v8.19+),并会自动安装。它还需要 PSR-18 HTTP 客户端——如果你尚未安装:
composer require guzzlehttp/guzzle guzzlehttp/psr7
2. 发布配置
php artisan vendor:publish --tag=auth0
这会创建 config/auth0.php,其中包含 guard、中间件和路由配置。
3. 创建 Auth0 API
你需要在 Auth0 中创建一个 API(而非 Application)。
停止——继续之前先询问用户。
确切地询问以下问题,并等待用户回答后再进行任何其他操作:
"你希望如何创建 Auth0 API 资源?
- 自动创建——我将运行 Auth0 CLI 脚本来创建资源,并自动将确切的值写入你的
.env。- 手动创建——你在 Auth0 Dashboard 中自行创建 API(或通过
auth0 apis create创建),并向我提供 Domain 和 Audience。你更倾向于哪种方式?(1 = 自动创建 / 2 = 手动创建)"
在用户回答之前,不要继续任何设置步骤。不要默认选择手动创建。
如果用户选择自动创建,请遵循设置指南中的完整 CLI 脚本。自动创建流程会替你写入 .env——跳过下面的第 4 步,直接进入第 5 步。
如果用户选择手动创建,请遵循设置指南中的“手动设置”部分,查看完整说明。然后继续下面的第 4 步。
手动创建 API 的快速参考:
auth0 apis create \
--name "My Laravel API" \
--identifier https://my-api.example.com \
--json
也可以在 Auth0 Dashboard -> Applications -> APIs 中手动创建
4. 配置环境
将以下内容添加到你的 .env:
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_AUDIENCE=https://your-api.example.com
AUTH0_DOMAIN 是你的 Auth0 租户域名(不带 https://)。AUTH0_AUDIENCE 是你在 Auth0 中创建 API 资源时设置的 API 标识符。
5. 配置 Auth Guard
更新 config/auth.php,添加 API guard:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'auth0-api' => [
'driver' => 'auth0.authorizer',
'provider' => 'auth0-provider',
'configuration' => 'api',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'auth0-provider' => [
'driver' => 'auth0.provider',
'repository' => 'auth0.repository',
],
],
要点:
driver必须是auth0.authorizer(不能使用面向 Web 应用的auth0.authenticator)configuration必须为'api',它会映射到config/auth0.php中的apiguard- SDK 会使用此配置自动注册
auth0-apiguard,但显式定义会更加清晰
6. 验证 Auth0 配置
发布配置后,验证 config/auth0.php 包含 guards.api 键,且其 strategy 设置为 SdkConfiguration::STRATEGY_API(值为 'api')。已发布的配置中已经包含此项,无需手动编辑。
已发布的文件使用类常量作为键(例如 Configuration::CONFIG_STRATEGY),这些常量在运行时会解析为相同的字符串值:
'guards' => [
'api' => [
'strategy' => SdkConfiguration::STRATEGY_API, // value: 'api'
],
],
已发布的配置还包含 default 和 web guard 部分——仅用于 API 的场景可以忽略它们。STRATEGY_API 策略会禁用所有会话/ Cookie 机制,并启用无状态 Bearer 令牌验证。
7. 添加受保护的 API 路由
Laravel 11+ 默认不包含 routes/api.php。如果该文件不存在,请创建它:
php artisan install:api
此操作会创建 routes/api.php,并在 bootstrap/app.php 中为其注册 /api 前缀。它还会安装 Laravel Sanctum;虽然这里不会用到,但与 Auth0 一起使用也不会造成问题。
在 routes/api.php 中:
use Illuminate\Support\Facades\Route;
Route::get('/public', function () {
return response()->json(['message' => 'Public endpoint - no authentication required']);
});
Route::middleware('auth:auth0-api')->group(function () {
Route::get('/private', function () {
$user = auth('auth0-api')->user();
return response()->json([
'message' => 'Private endpoint',
'sub' => $user->getAuthIdentifier(),
]);
});
});
auth:auth0-api 中间件会验证 Bearer 令牌,根据 JWKS 端点验证签名,并检查颁发者和受众声明。没有有效令牌的请求会收到 401 响应。
8. 作用域和权限检查
使用 guard 的 hasScope() 和 hasPermission() 方法:
Route::middleware('auth:auth0-api')->group(function () {
Route::get('/messages', function () {
$guard = auth('auth0-api');
if (!$guard->hasScope('read:messages')) {
return response()->json(['error' => 'insufficient_scope'], 403);
}
return response()->json(['messages' => []]);
});
Route::delete('/users/{id}', function (string $id) {
$guard = auth('auth0-api');
if (!$guard->hasPermission('delete:users')) {
return response()->json(['error' => 'insufficient_permissions'], 403);
}
return response()->json(['deleted' => $id]);
});
});
hasScope()检查scope声明(JWT 中以空格分隔的字符串)hasPermission()检查permissions声明(数组;需要在 Auth0 Dashboard 中为 API 启用 RBAC)
9. 访问令牌声明
经过身份验证的用户是一个 StatelessUser 实例,可动态访问声明:
Route::middleware('auth:auth0-api')->get('/profile', function () {
$user = auth('auth0-api')->user();
return response()->json([
'sub' => $user->getAuthIdentifier(),
'email' => $user->email,
'permissions' => $user->permissions ?? [],
'all_claims' => $user->jsonSerialize(),
]);
});
通过以下方式访问声明:
$user->getAuthIdentifier()- 返回sub声明$user->claim_name- 通过__get动态访问属性$user->getAttribute('claim_name')- 显式访问$user->jsonSerialize()- 返回包含所有声明的数组
10. 测试 API
**Agent 指令:**启动 Laravel 开发服务器,并验证无需凭据即可正常使用基本端点:
php artisan serve & sleep 2 curl -s -H "Accept: application/json" http://localhost:8000/api/public curl -s -o /dev/null -w "%{http_code}" -H "Accept: application/json" http://localhost:8000/api/private
/api/public应返回{"message":"Public endpoint - no authentication required"}/api/private应返回 HTTP 401**重要:**必须提供
-H "Accept: application/json"标头。否则,Laravel 的Authenticate中间件会返回 302 重定向,而不是 401。如果两项测试都通过,则 guard 正常工作。完成后关闭后台服务器:
kill %1 2>/dev/null**故障检查:**如果服务器启动失败或响应不符合预期,请检查
config/auth0.php是否存在,以及.env中是否设置了AUTH0_DOMAIN和AUTH0_AUDIENCE。失败迭代 5-6 次后,请使用AskUserQuestion。
Agent 指令:停止——基本测试通过后询问用户。
/api/public和 401 测试通过后,询问用户:“你的 API 已设置完成,guard 也正常工作(无令牌时,public 返回 200,private 返回 401)。你希望我帮你设置使用真实访问令牌进行测试吗?
- 是——我会帮你配置 M2M 应用以获取测试令牌。
- 否——我暂时就到这里。
你更倾向哪种?”
除非用户同意,否则不要继续设置 M2M/令牌。
Agent 指令(M2M 应用设置——仅在用户希望测试时执行):
如果用户选择设置测试,请询问:
“要测试受保护的端点,你需要一个已获授权、可为此 API 请求令牌的 Machine-to-Machine (M2M) 应用。
- 新建——我会创建一个新的 M2M 应用,并为此 API 授权。
- 使用现有应用——你已有 M2M 应用。请提供 Client ID,我会为此 API 授权。
你更倾向哪种?(1 = 新建 / 2 = 使用现有应用)”
在用户回答前不要继续。
如果用户选择“新建”:
auth0 apps create \ --name "${PWD##*/} (Test App)" \ --type m2m \ --no-input --json使用
jq解析 JSON 并提取client_id。不要使用--reveal-secrets。 然后创建 client grant:auth0 api post "client-grants" --data '{ "client_id": "<CLIENT_ID>", "audience": "<API_IDENTIFIER>", "scope": ["<SCOPES>"] }'如果用户选择“使用现有应用”: 询问 Client ID。创建 client grant(409 冲突表示已获授权,可忽略)。 Agent 指令(令牌隔离 - 至关重要):
Agent 绝不能直接查看或显示访问令牌值。
- 不要单独运行
auth0 test token- 不要要求用户粘贴其令牌
- 不要回显或存储令牌值
安全测试(单命令链):
php artisan serve & sleep 2 TEST_TOKEN=$(auth0 test token <M2M_CLIENT_ID> --audience <AUDIENCE> --scopes <SCOPE1,SCOPE2> 2>/dev/null | grep -o 'ey[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*') && \ [ -n "$TEST_TOKEN" ] && echo "Token acquired (${#TEST_TOKEN} chars)" && \ curl -s -H "Accept: application/json" -H "Authorization: Bearer $TEST_TOKEN" http://localhost:8000/api/private kill %1 2>/dev/null如果用户没有要求测试,请提供以下命令供其手动运行:
auth0 test token <CLIENT_ID> --audience <AUDIENCE> --scopes <SCOPE1,SCOPE2> curl -H "Accept: application/json" -H "Authorization: Bearer <PASTE_TOKEN_HERE>" http://localhost:8000/api/private
启动服务:
php artisan serve
测试公共端点(无需令牌):
curl -H "Accept: application/json" http://localhost:8000/api/public
测试不带令牌的受保护端点(应返回 401):
curl -H "Accept: application/json" http://localhost:8000/api/private
注意:必须提供 Accept: application/json 标头。否则,Laravel 会重定向(302),而不是返回 401。
使用令牌测试受保护端点:
curl http://localhost:8000/api/private \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
通过 Auth0 Dashboard -> APIs -> Test 选项卡获取测试令牌,或通过上述 M2M 流程获取。
常见错误
| 错误 | 修正方法 |
|---|---|
在 API 路由中使用 auth0.authenticator 驱动 | API 守卫必须使用 auth0.authorizer——auth0.authenticator 适用于基于会话的 Web 应用 |
在 API 路由中使用 auth:web 中间件 | 使用 auth:auth0-api 指定 API 守卫 |
| 在 Auth0 中创建了 Application,而不是 API | 必须创建 API 资源(Dashboard -> Applications -> APIs) |
使用带 https:// 前缀的 domain | 使用不带前缀的域名:tenant.us.auth0.com,而不是 https://tenant.us.auth0.com |
直接使用 auth0/auth0-php | 使用 auth0/login,它通过 Laravel 守卫和中间件封装了 SDK |
| 未发布配置 | 配置前运行 php artisan vendor:publish --tag=auth0 |
.env 中缺少 AUTH0_AUDIENCE | 令牌验证所必需——没有它,就无法针对正确的受众验证令牌 |
使用 $request->user() 时未指定守卫名称 | 默认使用 web 守卫——请使用 auth('auth0-api')->user() 或 $request->user('auth0-api') |
将 $user->scope 当作字符串检查 | JWT 中的 scope 声明以空格分隔——请使用 hasScope(),而不是字符串比较 |
未启用 RBAC 就调用 hasPermission() | 必须在 Auth0 Dashboard -> APIs -> Settings 中启用 “Add Permissions in the Access Token” |
| 使用 ID 令牌进行 API 身份验证 | 必须使用 访问令牌——ID 令牌供客户端应用使用 |
在 API 守卫上设置 configuration => 'web' | 必须设为 'api',它映射到 config/auth0.php 中的 STRATEGY_API 配置 |
使用 curl 测试时未提供 Accept: application/json 标头 | Laravel 会返回 302 重定向,而不是 401——API 请求始终发送 Accept: application/json |
对 API 中未定义的作用域调用 hasScope() 时返回 false | 必须在 Auth0 Dashboard 中的 API 资源上定义作用域——在令牌请求中请求某个作用域并不会授予该作用域,除非已定义 |
对 M2M 令牌调用 hasPermission() 时返回 false | RBAC 权限仅嵌入基于用户的流程(Authorization Code)所颁发的令牌中,不会嵌入客户端凭据授权所颁发的令牌中 |
Laravel 11+ 中缺少 routes/api.php | 运行 php artisan install:api 以搭建 API 路由——Laravel 11 默认不包含该文件 |
SDK 关键方法
| 方法 | 返回值 | 用途 |
|---|---|---|
auth('auth0-api')->user() | ?StatelessUser | 返回已验证身份的用户,若无则返回 null |
auth('auth0-api')->check() | bool | 检查请求是否包含有效令牌 |
auth('auth0-api')->hasScope($scope) | bool | 检查令牌是否具有特定作用域 |
auth('auth0-api')->hasPermission($perm) | bool | 检查令牌是否具有特定 RBAC 权限 |
auth('auth0-api')->id() | ?string | 直接返回 sub 声明 |
$user->getAuthIdentifier() | int|string|null | 返回 sub 声明 |
$user->getAttribute('key') | mixed | 返回任意声明值 |
$user->jsonSerialize() | array | 以数组形式返回所有声明 |
auth('auth0-api')->getCredential() | ?CredentialEntity | 包含已解码令牌数据的完整凭据 |
相关技能
auth0-laravel- 用于使用基于会话的身份验证实现登录/注销的 Laravel Web 应用auth0-php-api- 用于不使用 Laravel 的纯 PHP APIauth0-quickstart- Auth0 初始设置auth0-mfa- 添加多因素身份验证auth0-cli- 从终端管理 Auth0 资源
快速参考
Guard 配置(config/auth.php):
'guards' => [
'auth0-api' => [
'driver' => 'auth0.authorizer',
'provider' => 'auth0-provider',
'configuration' => 'api',
],
],
'providers' => [
'auth0-provider' => [
'driver' => 'auth0.provider',
'repository' => 'auth0.repository',
],
],
路由保护:
Route::middleware('auth:auth0-api')->group(function () {
Route::get('/resource', fn() => response()->json([...]));
});
作用域/权限检查:
$guard = auth('auth0-api');
$guard->hasScope('read:messages'); // checks scope claim
$guard->hasPermission('delete:users'); // checks permissions claim (RBAC)
用户声明:
$user = auth('auth0-api')->user();
$user->getAuthIdentifier(); // sub
$user->email; // any claim via __get
$user->getAttribute('iss'); // explicit claim access
环境变量:
AUTH0_DOMAIN- Auth0 租户域名(例如tenant.us.auth0.com)AUTH0_AUDIENCE- API 标识符(例如https://api.example.com)
常见用例:
- 保护路由 ->
auth:auth0-api中间件(参见步骤 7) - 强制执行作用域 ->
hasScope()(参见步骤 8) - 强制执行权限 ->
hasPermission()(参见步骤 8) - 高级配置 -> API 参考
详细文档
- 设置指南 - Auth0 CLI 设置、环境配置、获取测试令牌
- 集成指南 - 作用域、权限、CORS、自定义用户存储库、错误处理、多 Guard
- API 参考 - 完整的 AuthorizationGuard API、StatelessUser、CredentialEntity、配置选项