Files
alterminal/internal/oidc/discovery.go
T
2026-10-03 12:37:38 +08:00

66 lines
3.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package oidc
import (
"fmt"
"net/http"
"alterminal/internal/application"
"alterminal/internal/auth"
)
// discoveryMaxAge 為 Discovery 文件的建議快取秒數,與 JWKS 一致:內容
// 僅在部署設定變更時改變。
const discoveryMaxAge = 3600
// discoveryDocument 為 OIDC Discovery 文件(OIDC Discovery 1.0 §3)。
// 本服務僅支援授權碼流程(RFC 6749 §4.1.1)與 refresh token grant
// (§6);subject type 僅 public(sub 對使用者恆為同一值)。
type discoveryDocument struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
UserInfoEndpoint string `json:"userinfo_endpoint"`
EndSessionEndpoint string `json:"end_session_endpoint"` // RP-Initiated Logout 1.0 §2.1:同時支援兩者時為 REQUIRED
JWKSURI string `json:"jwks_uri"`
ScopesSupported []string `json:"scopes_supported"`
ResponseTypesSupported []string `json:"response_types_supported"`
ResponseModesSupported []string `json:"response_modes_supported"`
GrantTypesSupported []string `json:"grant_types_supported"`
SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"`
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"`
ClaimsSupported []string `json:"claims_supported"`
}
// DiscoveryHandler 處理 GET /.well-known/openid-configuration:發佈本
// 服務的 OIDC 端點與能力中繼資料,供 RP 以標準方式取得組態。issuer 於
// main 讀取 ISSUER 環境變數後注入——issuer 字串須與簽入 token 的 iss
// claim 完全一致(OIDC Core §3.1.3.7 的 issuer 驗證)。
func DiscoveryHandler(issuer string) http.HandlerFunc {
doc := discoveryDocument{
Issuer: issuer,
AuthorizationEndpoint: issuer + "/authorize",
TokenEndpoint: issuer + "/token",
UserInfoEndpoint: issuer + "/userinfo",
EndSessionEndpoint: issuer + "/logout",
JWKSURI: issuer + "/.well-known/jwks.json",
ScopesSupported: application.ScopesSupported(),
ResponseTypesSupported: []string{"code"},
ResponseModesSupported: []string{"query"},
GrantTypesSupported: []string{"authorization_code", "refresh_token"},
SubjectTypesSupported: []string{"public"},
IDTokenSigningAlgValuesSupported: []string{"RS256"},
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic", "client_secret_post", "none"},
CodeChallengeMethodsSupported: []string{"S256"},
ClaimsSupported: []string{
"sub", "iss", "aud", "exp", "iat", "auth_time", "nonce",
"name", "preferred_username", "email", "email_verified",
},
}
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%d", discoveryMaxAge))
auth.WriteJSON(w, http.StatusOK, doc)
}
}