first commit

This commit is contained in:
2026-10-03 10:44:29 +08:00
parent f373cb8d37
commit bcf3d3769c
58 changed files with 4313 additions and 487 deletions
+63
View File
@@ -0,0 +1,63 @@
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"`
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",
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)
}
}