From d4b627e4e3f5c3ce98f5725962bec87fbe210f92 Mon Sep 17 00:00:00 2001 From: M Hickford Date: Thu, 6 Oct 2022 06:03:52 +0100 Subject: [PATCH] Parse OAuth Authorization header when request omits client secret (#21351) This fixes error "unauthorized_client: invalid client secret" when client includes secret in Authorization header rather than request body. OAuth spec permits both. 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 Co-authored-by: zeripath --- routers/web/auth/oauth.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 56f8294b1a9d9..a9fc39d0195c1 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -588,7 +588,8 @@ func OIDCKeys(ctx *context.Context) { // AccessTokenOAuth manages all access token requests by the client func AccessTokenOAuth(ctx *context.Context) { form := *web.GetForm(ctx).(*forms.AccessTokenForm) - if form.ClientID == "" { + // 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 + if form.ClientID == "" || form.ClientSecret == "" { authHeader := ctx.Req.Header.Get("Authorization") authContent := strings.SplitN(authHeader, " ", 2) if len(authContent) == 2 && authContent[0] == "Basic" { @@ -608,7 +609,21 @@ func AccessTokenOAuth(ctx *context.Context) { }) return } + if form.ClientID != "" && form.ClientID != pair[0] { + handleAccessTokenError(ctx, AccessTokenError{ + ErrorCode: AccessTokenErrorCodeInvalidRequest, + ErrorDescription: "client_id in request body inconsistent with Authorization header", + }) + return + } form.ClientID = pair[0] + if form.ClientSecret != "" && form.ClientSecret != pair[1] { + handleAccessTokenError(ctx, AccessTokenError{ + ErrorCode: AccessTokenErrorCodeInvalidRequest, + ErrorDescription: "client_secret in request body inconsistent with Authorization header", + }) + return + } form.ClientSecret = pair[1] } } @@ -686,9 +701,13 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s return } if !app.ValidateClientSecret([]byte(form.ClientSecret)) { + errorDescription := "invalid client secret" + if form.ClientSecret == "" { + errorDescription = "invalid empty client secret" + } handleAccessTokenError(ctx, AccessTokenError{ ErrorCode: AccessTokenErrorCodeUnauthorizedClient, - ErrorDescription: "client is not authorized", + ErrorDescription: errorDescription, }) return }