chore: drop "oidc_wellknown" tmpl, use json directly (#38731)

`testOAuth2WellKnown` already covers the endpoint's response.
This commit is contained in:
wxiaoguang
2026-07-31 18:32:01 +02:00
committed by GitHub
parent f0a95eebe3
commit 76a787a79d
9 changed files with 81 additions and 90 deletions
-3
View File
@@ -22,9 +22,6 @@ insert_final_newline = false
indent_style = space
insert_final_newline = false
[templates/user/auth/oidc_wellknown.tmpl]
indent_style = space
[templates/shared/actions/runner_badge_*.tmpl]
# editconfig lint requires these XML-like files to have charset defined, but the files don't have.
charset = unset
-14
View File
@@ -472,20 +472,6 @@ func GrantApplicationOAuth(ctx *context.Context) {
ctx.Redirect(redirect.String(), http.StatusSeeOther)
}
// OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities
func OIDCWellKnown(ctx *context.Context) {
if !setting.OAuth2.Enabled {
http.NotFound(ctx.Resp, ctx.Req)
return
}
jwtRegisteredClaims := oauth2_provider.NewJwtRegisteredClaimsFromUser("well-known", 0, nil)
ctx.Data["OidcIssuer"] = jwtRegisteredClaims.Issuer // use the consistent issuer from the JWT registered claims
ctx.Data["OidcBaseUrl"] = strings.TrimSuffix(setting.AppURL, "/")
ctx.Data["SigningKeyMethodAlg"] = oauth2_provider.DefaultSigningKey.SigningMethod().Alg()
// FIXME: no need to use a Golang template to render JSON, just build the JSON response directly in the future
ctx.JSONTemplate("user/auth/oidc_wellknown")
}
// OIDCKeys generates the JSON Web Key Set
func OIDCKeys(ctx *context.Context) {
jwk, err := oauth2_provider.DefaultSigningKey.ToJWK()
+70
View File
@@ -0,0 +1,70 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package auth
import (
"net/http"
"strings"
"gitea.dev/modules/setting"
"gitea.dev/services/context"
"gitea.dev/services/oauth2_provider"
)
// OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities
func OIDCWellKnown(ctx *context.Context) {
if !setting.OAuth2.Enabled {
http.NotFound(ctx.Resp, ctx.Req)
return
}
jwtRegisteredClaims := oauth2_provider.NewJwtRegisteredClaimsFromUser("well-known", 0, nil)
oidcIssuer := jwtRegisteredClaims.Issuer // use the consistent issuer from the JWT registered claims
oidcBaseUrl := strings.TrimSuffix(setting.AppURL, "/")
m := map[string]any{
"issuer": oidcIssuer,
"authorization_endpoint": oidcBaseUrl + "/login/oauth/authorize",
"token_endpoint": oidcBaseUrl + "/login/oauth/access_token",
"jwks_uri": oidcBaseUrl + "/login/oauth/keys",
"userinfo_endpoint": oidcBaseUrl + "/login/oauth/userinfo",
"introspection_endpoint": oidcBaseUrl + "/login/oauth/introspect",
"response_types_supported": []string{
"code",
"id_token",
},
"id_token_signing_alg_values_supported": []string{
oauth2_provider.DefaultSigningKey.SigningMethod().Alg(),
},
"subject_types_supported": []string{
"public",
},
"scopes_supported": oauth2_provider.GeneralScopesSupported(),
"claims_supported": []string{
"aud",
"exp",
"iat",
"iss",
"sub",
"name",
"preferred_username",
"profile",
"picture",
"website",
"locale",
"updated_at",
"email",
"email_verified",
"groups",
},
"code_challenge_methods_supported": []string{
"plain",
"S256",
},
"grant_types_supported": []string{
"authorization_code",
"refresh_token",
},
}
ctx.JSON(http.StatusOK, m)
}
+1 -1
View File
@@ -114,7 +114,7 @@ func (b *Base) HTTPError(status int, contents ...string) {
func (b *Base) JSON(status int, content any) {
b.Resp.Header().Set("Content-Type", "application/json;charset=utf-8")
b.Resp.WriteHeader(status)
if err := json.NewEncoder(b.Resp).Encode(content); err != nil {
if err := json.MarshalWrite(b.Resp, content); err != nil {
log.Error("Render JSON failed: %v", err)
}
}
-14
View File
@@ -104,20 +104,6 @@ func (ctx *Context) HTML(status int, name templates.TplName) {
}
}
// JSONTemplate renders the template as JSON response
// keep in mind that the template is processed in HTML context, so JSON things should be handled carefully, e.g.: use JSEscape
func (ctx *Context) JSONTemplate(tmpl templates.TplName) {
t, err := ctx.Render.TemplateLookup(string(tmpl), nil)
if err != nil {
ctx.ServerError("unable to find template", err)
return
}
ctx.Resp.Header().Set("Content-Type", "application/json")
if err = t.Execute(ctx.Resp, ctx.Data); err != nil {
ctx.ServerError("unable to execute template", err)
}
}
// RenderToHTML renders the template content to a HTML string
func (ctx *Context) RenderToHTML(name templates.TplName, data any) (template.HTML, error) {
var buf strings.Builder
+4 -4
View File
@@ -360,7 +360,7 @@ func UploadHandler(ctx *context.Context) {
return err
}
} else {
log.Error("Unable to check if LFS OID[%s] stat. Error: %v", p.Oid, err)
log.Error("Unable to check LFS OID[%s] stat. Error: %v", p.Oid, err)
return err
}
_, err = git_model.NewLFSMetaObject(ctx, repository.ID, p)
@@ -378,10 +378,10 @@ func UploadHandler(ctx *context.Context) {
}
// Do not remove the LFS MetaObject here: this request only creates it after the content is verified and stored,
// an invalid request should not remove the existing correct record.
// If two requests are loading (the file is incomplete):
// If two requests are uploading (the file is incomplete):
// * one will keep writing the file content
// * one will fail the verification because it reads an incomplete file, the failure should be just ignore
// In the end, the first one will complete the upload and insert a LFS MetaObject record.
// * one will fail the verification because it reads an incomplete file, the failure should be just be ignored
// In the end, the first one will complete the upload and insert a new LFS MetaObject record.
return
}
+6 -4
View File
@@ -74,16 +74,18 @@ type AccessTokenResponse struct {
IDToken string `json:"id_token,omitempty"`
}
// GrantAdditionalScopes returns valid scopes coming from grant
func GrantAdditionalScopes(grantScopes string) auth.AccessTokenScope {
// scopes_supported from templates/user/auth/oidc_wellknown.tmpl
generalScopesSupported := []string{
func GeneralScopesSupported() []string {
return []string{
"openid",
"profile",
"email",
"groups",
}
}
// GrantAdditionalScopes returns valid scopes coming from grant
func GrantAdditionalScopes(grantScopes string) auth.AccessTokenScope {
generalScopesSupported := GeneralScopesSupported()
var accessScopes []string // the scopes for access control, but not for general information
for scope := range strings.SplitSeq(grantScopes, " ") {
if scope != "" && !slices.Contains(generalScopesSupported, scope) {
-1
View File
@@ -26,7 +26,6 @@ export default {
prefix: 'tw-',
important: true, // the frameworks are mixed together, so tailwind needs to override other framework's styles
content: [
'!./templates/user/auth/oidc_wellknown.tmpl',
'!**/*_test.go',
'./{build,models,modules,routers,services}/**/*.go',
'./templates/**/*.tmpl',
-49
View File
@@ -1,49 +0,0 @@
{
"issuer": "{{.OidcIssuer}}",
"authorization_endpoint": "{{.OidcBaseUrl}}/login/oauth/authorize",
"token_endpoint": "{{.OidcBaseUrl}}/login/oauth/access_token",
"jwks_uri": "{{.OidcBaseUrl}}/login/oauth/keys",
"userinfo_endpoint": "{{.OidcBaseUrl}}/login/oauth/userinfo",
"introspection_endpoint": "{{.OidcBaseUrl}}/login/oauth/introspect",
"response_types_supported": [
"code",
"id_token"
],
"id_token_signing_alg_values_supported": [
"{{.SigningKeyMethodAlg}}"
],
"subject_types_supported": [
"public"
],
"scopes_supported": [
"openid",
"profile",
"email",
"groups"
],
"claims_supported": [
"aud",
"exp",
"iat",
"iss",
"sub",
"name",
"preferred_username",
"profile",
"picture",
"website",
"locale",
"updated_at",
"email",
"email_verified",
"groups"
],
"code_challenge_methods_supported": [
"plain",
"S256"
],
"grant_types_supported": [
"authorization_code",
"refresh_token"
]
}