Laravel Passport授权码模式需三处对齐:/oauth/authorize路由必须用web中间件、客户端为confidential类型且redirect严格匹配、授权URL参数规范;获取code后须用服务端POST请求/oauth/token换取access_token。

Laravel Passport 授权码模式(Authorization Code Grant)是 Web 应用对接第三方登录或安全接入最常用、也最推荐的方式。它不是配完 passport:install 就能跑通的,关键在三处对齐:路由中间件、客户端类型、重定向地址。稍有不一致,就会卡在 /oauth/authorize 跳转失败、CSRF 报错、或回调拿不到 code。
/oauth/authorize 路由必须走 web 中间件
这个接口本质是面向浏览器的授权页面(带登录表单和“允许/拒绝”按钮),依赖 session 和 CSRF token。
- ✅ 正确:
Route::get('/oauth/authorize', [\Laravel\Passport\Http\Controllers\AuthorizationController::class, 'authorize'])->middleware('web'); - ❌ 错误:加
api中间件,或没显式指定中间件(Laravel 10+ 默认api组不带 session) - 若你用的是 Laravel 11+,确保
AuthServiceProvider::boot()中调用了:Passport::routes(); // 注册所有默认路由 Passport::enableAuthorizationCodeGrant(); // 显式启用授权码模式
客户端必须是 confidential 类型且 redirect 严格匹配
数据库 oauth_clients 表中,该客户端需满足:
-
personal_access_client = 0 -
password_client = 0 -
redirect字段值必须与你发起授权请求时传的redirect_uri完全一致(协议、域名、端口、路径、末尾斜杠都不能差)- 例如数据库存的是
https://app.example.com/callback/,那你请求时就不能写成https://app.example.com/callback或http://...
- 例如数据库存的是
-
client_secret必须存在(不能为 null),且调用/oauth/token换 token 时必须带上
? 提示:用
php artisan passport:client --confidential创建,比手动插入更稳妥。
构造授权 URL 要规范,scope 是空格分隔字符串
前端跳转到 /oauth/authorize 时,参数必须完整、格式正确:
-
response_type=code(固定) -
client_id=xxx(对应数据库中的 id) -
redirect_uri=https://your-app.com/callback(必须编码) -
scope=read write profile(空格分隔,不是数组、不是逗号) -
state=随机字符串(用于防 CSRF,务必校验回调时是否一致)
示例完整 URL:
https://your-api.com/oauth/authorize? response_type=code& client_id=3& redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback& scope=read%20write& state=abc123xyz
拿到 code 后,立刻换 access_token
用户点击“允许”后,会跳回你的 redirect_uri,URL query 中带 code=xxx&state=abc123xyz。
此时需立即向 /oauth/token 发起 POST 请求(服务端调用,绝不暴露 client_secret 到前端):
-
grant_type=authorization_code -
client_id=3 -
client_secret=xxx(数据库里查出的 secret) -
redirect_uri=同上,必须一字不差 -
code=xxx(刚收到的一次性 code)
成功响应含 access_token、refresh_token、expires_in 等字段。token 默认 1 小时过期,可用 refresh_token 刷新。
不复杂但容易忽略











