快速入門:任何 OIDC 程式庫
Usher 是標準的 OpenID Connect 提供者。如果你使用的語言有經過認證的 OIDC 客户端,你就已經具備所需的一切:將它指向你環境的探索文件,並使用搭配 PKCE 的授權碼流程。
設定
| 設定 | 值 |
|---|---|
| 簽發者 | https://<handle>.usherid.com |
| 探索 URL | https://<handle>.usherid.com/.well-known/openid-configuration |
| 流程 | 授權碼(response_type=code) |
| PKCE | 必要,code_challenge_method=S256 |
| 範圍 | openid profile email offline_access |
| 客户端驗證 | 按 token_endpoint_auth_methods_supported 中列出的方式 |
你環境的代號顯示在 Usher Console 中簽發者的旁邊。開發環境會取得隨機代號,例如 wise-otter-42;正式環境則使用你選擇的代號。正式環境也可以改用你自己的網域,例如 login.acme.com:只要你以 CNAME 記錄將該網域指向 Usher,它就會成為該環境的簽發者。
讀取探索文件
你的客户端需要的每個端點和密鑰都列在這裡。請讓你的程式庫讀取它,而不是把 URL 寫死在程式碼中。
curl -s https://acme.usherid.com/.well-known/openid-configuration | jq{
"issuer": "https://acme.usherid.com",
"authorization_endpoint": "https://acme.usherid.com/api/auth/oauth2/authorize",
"token_endpoint": "https://acme.usherid.com/api/auth/oauth2/token",
"userinfo_endpoint": "https://acme.usherid.com/api/auth/oauth2/userinfo",
"jwks_uri": "https://acme.usherid.com/api/auth/jwks",
"introspection_endpoint": "https://acme.usherid.com/api/auth/oauth2/introspect",
"revocation_endpoint": "https://acme.usherid.com/api/auth/oauth2/revoke",
"end_session_endpoint": "https://acme.usherid.com/api/auth/oauth2/end-session",
"scopes_supported": ["openid", "profile", "email", "offline_access"],
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token", "client_credentials"],
"code_challenge_methods_supported": ["S256"]
}流程
將用户送往授權端點
產生一個隨機的 PKCE 驗證器,連同一個隨機的 state,保存在只有這個瀏覽器的工作階段才能存取的地方(短效的 httpOnly Cookie 就很適合)。然後帶著 response_type=code、你的 client_id 和 redirect_uri、上述範圍、state,以及驗證器的 S256 code_challenge 進行重新導向。
讓他們登入
接下來交給 Lobby:它會指出你的 App、提供你環境允許的登入方式,並在第一次時徵求同意。
檢查回呼
Usher 會帶著 code 和 state 重新導向到你的 redirect_uri。除非 state 與你儲存的相符,否則請拒絕該回應。授權碼只能使用一次,有效期為五分鐘。
用授權碼換取權杖
從你的伺服器,將授權碼和 PKCE 驗證器 POST 到權杖端點:
curl -s -X POST https://acme.usherid.com/api/auth/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code="$CODE" \
-d redirect_uri=https://app.acme.example/callback \
-d code_verifier="$CODE_VERIFIER"驗證 ID 權杖
以 jwks_uri 的密鑰檢查它的簽名,並確認 iss 是你的簽發者、aud 是你的客户端 ID,且 exp 是未來的時間。你的程式庫會替你完成這些檢查;請確認這項功能沒有被關閉。
在 Node.js 中
openid-client 會完成上述所有步驟,包括驗證:
import * as client from 'openid-client'
// discovery: every endpoint and key comes from the issuer
const config = await client.discovery(
new URL('https://acme.usherid.com'),
process.env.USHER_CLIENT_ID!,
process.env.USHER_CLIENT_SECRET!,
)
// 1. send them to the Lobby, with PKCE (S256) and a state to check later
const codeVerifier = client.randomPKCECodeVerifier()
const state = client.randomState()
const url = client.buildAuthorizationUrl(config, {
redirect_uri: 'https://app.acme.example/callback',
scope: 'openid profile email offline_access',
code_challenge: await client.calculatePKCECodeChallenge(codeVerifier),
code_challenge_method: 'S256',
state,
})
// keep codeVerifier and state in a short-lived httpOnly cookie, then redirect to url
// 2. back at /callback: swap the code for tokens
const tokens = await client.authorizationCodeGrant(config, new URL(request.url), {
pkceCodeVerifier: codeVerifier,
expectedState: state,
})
const { sub, email, name } = tokens.claims()!在其他語言中
以下這些廣泛使用的程式庫都支援標準 OpenID Connect,不需要任何 Usher 專屬的設定就能搭配 Usher 使用:
| 語言 | 程式庫 |
|---|---|
| Python | Authlib |
| Go | coreos/go-oidc 搭配 golang.org/x/oauth2 |
| Java | Spring Security OAuth 2.0 Client |
| .NET | Microsoft.AspNetCore.Authentication.OpenIdConnect |
| Ruby | omniauth_openid_connect |
| PHP | jumbojett/openid-connect-php |
保持登入
使用 offline_access 範圍時,權杖回應會包含重新整理權杖。當舊的存取權杖到期時,搭配 grant_type=refresh_token 使用它來取得新的存取權杖。重新整理權杖會輪替:每次使用都會傳回新的權杖,舊的則會失效。
登出
先清除你自己的工作階段,然後帶著 post_logout_redirect_uri(如果有的話,再加上 id_token_hint)重新導向到 end_session_endpoint,讓 Lobby 也忘記這位用户。