OAuth 2.0 授權伺服器
讓第三方應用程式向你的使用者申請授權。這與「使用 Google 登入你的網站」是不同的功能。
Saavo 內建 OAuth 2.0 授權伺服器,讓你能將產品發展成開放平台。核心流程是由第三方應用程式引導使用者登入並授權,再以授權碼交換存取權杖,進而呼叫你開放的 API。
請注意,這與 Google 登入等社群帳號登入不同。社群登入是讓「外部身分進入你的系統」,Saavo 的授權伺服器則是讓「外部應用程式存取你的使用者資源」。
使用時,需要在開放的 API 中執行檢查,確認請求的權杖權限有效,且操作在允許的授權範圍內。
既有功能
範本初始化後,即可使用下列功能:
| 用途 | 預設入口 | 預設狀態 |
|---|---|---|
| 授權 | /oauth/authorize | oauth2.enableService 預設為 true |
| 登入後繼續 | /oauth/authorize/continue | 已啟用 |
| 同意頁面 | /oauth/authorize/consent | 已啟用 |
| 交換權杖 | POST /oauth/token | 已掛載 |
| 撤銷權杖 | POST /oauth/token/revoke | 已掛載 |
| 取得授權後的使用者資訊 | GET /oauth/current-user | 需要 user scope |
| 管理第三方用戶端 | /dashboard/oauth-server | 管理員可建立用戶端 |
範本預設支援授權碼、重新整理權杖與用戶端認證三種授權類型。其中,授權碼流程支援 PKCE 擴充,並強制使用 S256 演算法產生 Code Challenge。管理員建立 OAuth 用戶端時,可以設定回呼位址,並指定該用戶端允許的授權類型(Grant Type)與授權範圍(Scope)。
預設授權範圍位於 config/scopes.ts:
| Scope | 意義 |
|---|---|
user | 存取使用者資訊 |
basic | 範例的基本存取範圍 |
角色描述使用者本身擁有的權限,Scope 則描述某個存取權杖可以執行的操作。即使目前使用者是管理員,第三方應用程式取得的權杖也可能只有 basic Scope,因此只能存取該 basic Scope 允許的 API。

與 Google 登入有什麼不同
| 授權伺服器 | 社群登入 | |
|---|---|---|
| 目的 | 第三方應用程式存取你的 API | 使用者登入你的網站 |
| 頁面 | /oauth/authorize* | /auth/login 等 |
| 回呼/交換權杖 | /oauth/token | /api/auth/oauth2/google、/github |
| 設定 | deploy.oauth2、scopes.ts | GOOGLE_* / GITHUB_* 環境變數 |
/api/auth/current-user 讀取網站的 Session,/oauth/current-user 則讀取第三方應用程式的存取權杖,請勿混用。
先體驗授權流程
如果產品暫時不對第三方開放,仍建議先到後台查看用戶端管理頁面,避免上線後才發現預設開關已啟用。

完整操作一次授權碼流程:
管理員建立用戶端,填寫 Redirect URI 與允許的 scope
↓
第三方應用程式開啟 /oauth/authorize
↓
使用者登入(若尚未登入)
↓
在同意頁面確認權限
↓
帶回授權碼
↓
POST /oauth/token 交換 access token 與 refresh token預設授權碼有效期間為 15 分鐘,存取權杖為 1 天,重新整理權杖為 30 天。重新整理權杖會輪替。
提示
oauth2.enableService 只決定是否開放授權相關頁面,關閉後,/oauth/token 等 API 仍然可用。如果產品暫時不對第三方開放,建議不要建立任何用戶端,也不要在業務 API 中使用這些權杖。
設定 OAuth 2.0 授權伺服器
授權伺服器的相關設定,位於 config/deploy.ts 的 oauth2 區段與 config/scopes.ts。
是否開放 OAuth 2.0 服務
預設設定如下:
oauth2: {
enableService: true,
issuer: 'saavo',
requiresPKCE: true,
requiresS256: true,
}產品初始化後,建議及早修改 issuer。這個值會寫入存取權杖的宣告,用來識別權杖的簽發者。
如果產品不需要提供開放平台功能,可以將 enableService 設為 false,並且不建立 OAuth 用戶端。請注意,目前這個開關只控制相關頁面是否啟用,不會停止 OAuth API 本身。
如果希望完全停用授權伺服器,也需要停止掛載 /oauth 相關 API 路由。
定義第三方可申請的授權範圍
在 config/scopes.ts 新增自己的 scope,並填寫名稱與說明。這些文案會顯示在同意頁面。
第三方實際取得的權限,是請求的 scope 與用戶端允許的 scope 兩者的交集。只在設定中新增 scope 還不夠,也需要在後台將該 scope 授予對應用戶端。
設定授權範圍的升級提示
config/upgrade.ts 預設是空物件。當使用者缺少某項權益時,可以在這裡設定升級卡片,讓同意頁面引導使用者購買更高階的方案。
沒有升級需求就保持空白,不要將計費邏輯寫入以授權碼交換權杖的 API。
準備授權服務
OAuth 權杖的處理會用到專案的 SAAS_SECRET。依本文件的部署流程,同一專案的 .env 與 .env.production 必須保留相同的既有金鑰,不要在部署時臨時另產生一把。獨立的新專案應使用自己的金鑰,也不要將其他專案的金鑰複製過來。詳見保留既有的 SAAS_SECRET。
第三方用戶端使用的 Redirect URI,必須與管理後台登記的位址完全一致。本機開發與正式環境通常使用不同網域,可以分別建立對應環境的 OAuth 用戶端,也可以為同一個用戶端設定多組允許的回呼位址。
在業務 API 中驗證存取權杖
只有主動對第三方開放 API 時,才需要在業務路由中檢查 OAuth 權杖。
保護資源的基本原則是:
先檢查權杖的 scope,再視需要確認該使用者是否仍擁有某個角色或使用權益。不要將使用者的 admin 角色寫入權杖。
const result = await authz.authorizeOAuthRequest(c, {
scope: 'basic',
});
if (!result.success) {
return c.json(result, 401);
}如果這個 API 還要求使用者已購買某個產品:
const result = await authz.authorizeOAuthRequest(c, {
scope: 'user',
entitlement: 'starter_download',
});也可以個別使用:
await authz.hasScopes(c, 'user')
await authz.hasAnyScope(c, ['user', 'basic'])第三方應用程式透過 OAuth2 存取資源時,應只提供符合目前 Scope 的資料。範本提供的 GET /oauth/current-user 只是範例,即使通過 user Scope 檢查後會回傳部分使用者權益資訊,也不代表自己的資源 API 應照搬全部欄位。正式開放 API 時,應依實際業務決定哪些使用者資訊、角色或權益可以提供給第三方。
OAuth2 主要用於第三方用戶端存取 API。網站本身的頁面與第一方 API,仍繼續使用 Session 與 authenticatedGuard,不需要改用 Bearer Token 驗證。這兩種身分驗證方式適用於不同情境,不建議混用。
另外,透過 client_credentials 取得的權杖不代表任何特定使用者,因此不能依賴使用者角色、權益或其他個人狀態。它較適合服務之間的機器存取,這類 API 應僅依權杖的 Scope 決定是否允許存取。
提示
需要使用者授權時,使用授權碼與 PKCE 流程。服務之間不代表特定使用者的存取,才使用用戶端認證。重新整理權杖用來延續已核准的授權,範本也支援這個流程,不應將它歸類為不安全的授權類型。避免使用隱含式流程,也不要使用資源擁有者密碼憑證流程,相關說明請見 OAuth 安全最佳實務。
上線檢查
授權伺服器會將使用者權限提供給第三方,上線前建議至少確認:
-
issuer已改為自己的產品識別值。 -
SAAS_SECRET保留此專案既有的值,且.env與.env.production一致。 - 若不開放平台,未建立正式用戶端,且已關閉授權頁面。如果要求 API 也無法存取,已停止掛載
/oauth路由。 - 若開放平台,已使用授權碼與 PKCE 完成登入、同意、交換權杖、重新整理與撤銷流程。
- 用戶端 Redirect URI 已指向正式環境的回呼位址,不再使用本機位址。
- 業務 API 檢查的是 scope,而不是使用者是否為管理員。
- 權杖無法取得未申請的 scope。
- 授權範圍的文案已換成適合自己產品的說明。
建議使用專門的測試用戶端完成上述流程,不要以網站管理員的 Session 代替權杖測試。
常見問題
接下來
依接下來要開發的功能,可以繼續閱讀:
- 想讓使用者透過 Google 登入 → 串接 Google 登入
- 想限制使用者可以執行的操作 → 權限與使用權益
- 想在同意頁面推薦升級 → 付款與方案
- 想管理 OAuth 用戶端 → 管理後台
- 想了解身分驗證如何確認目前使用者 → 使用者身分驗證與帳號
大多數產品若只是提供自己的 SaaS 服務,不需要將授權伺服器視為核心功能。
只有確實要建立開放平台時,再以 scope 保護第三方 API。