Skip to content

Commit 982c3a7

Browse files
tyroneyehwxiaoguangzeripath
committed
Parse OAuth Authorization header when request omits client secret (go-gitea#21351) (go-gitea#21374)
Backport go-gitea#21351 This fixes error "unauthorized_client: invalid client secret" when client includes secret in Authorization header rather than request body. OAuth spec permits both: https://www.rfc-editor.org/rfc/rfc6749#section-2.3.1 Clients in possession of a client password MAY use the HTTP Basic authentication scheme ... Alternatively, the authorization server MAY support including the client credentials in the request-body Sanity validation that client id and client secret in request are consistent with Authorization header. Improve error descriptions. Error codes remain the same. Co-authored-by: wxiaoguang <[email protected]> Co-authored-by: zeripath <[email protected]>
1 parent 98927cd commit 982c3a7

File tree

1 file changed

+21
-2
lines changed

1 file changed

+21
-2
lines changed

routers/web/auth/oauth.go

+21-2
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,8 @@ func OIDCKeys(ctx *context.Context) {
588588
// AccessTokenOAuth manages all access token requests by the client
589589
func AccessTokenOAuth(ctx *context.Context) {
590590
form := *web.GetForm(ctx).(*forms.AccessTokenForm)
591-
if form.ClientID == "" {
591+
// if there is no ClientID or ClientSecret in the request body, fill these fields by the Authorization header and ensure the provided field matches the Authorization header
592+
if form.ClientID == "" || form.ClientSecret == "" {
592593
authHeader := ctx.Req.Header.Get("Authorization")
593594
authContent := strings.SplitN(authHeader, " ", 2)
594595
if len(authContent) == 2 && authContent[0] == "Basic" {
@@ -608,7 +609,21 @@ func AccessTokenOAuth(ctx *context.Context) {
608609
})
609610
return
610611
}
612+
if form.ClientID != "" && form.ClientID != pair[0] {
613+
handleAccessTokenError(ctx, AccessTokenError{
614+
ErrorCode: AccessTokenErrorCodeInvalidRequest,
615+
ErrorDescription: "client_id in request body inconsistent with Authorization header",
616+
})
617+
return
618+
}
611619
form.ClientID = pair[0]
620+
if form.ClientSecret != "" && form.ClientSecret != pair[1] {
621+
handleAccessTokenError(ctx, AccessTokenError{
622+
ErrorCode: AccessTokenErrorCodeInvalidRequest,
623+
ErrorDescription: "client_secret in request body inconsistent with Authorization header",
624+
})
625+
return
626+
}
612627
form.ClientSecret = pair[1]
613628
}
614629
}
@@ -686,9 +701,13 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s
686701
return
687702
}
688703
if !app.ValidateClientSecret([]byte(form.ClientSecret)) {
704+
errorDescription := "invalid client secret"
705+
if form.ClientSecret == "" {
706+
errorDescription = "invalid empty client secret"
707+
}
689708
handleAccessTokenError(ctx, AccessTokenError{
690709
ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
691-
ErrorDescription: "client is not authorized",
710+
ErrorDescription: errorDescription,
692711
})
693712
return
694713
}

0 commit comments

Comments
 (0)