diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index eba2b441c4..83be4eb154 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -792,6 +792,16 @@ func handleRefreshToken(ctx *context.Context, form forms.AccessTokenForm, server }) return } + + // Reject tokens that are not refresh tokens (e.g. access tokens submitted as refresh tokens) + if token.Type != oauth2.TypeRefreshToken { + handleAccessTokenError(ctx, AccessTokenErrorResponse{ + ErrorCode: AccessTokenErrorCodeUnauthorizedClient, + ErrorDescription: "token is not a refresh token", + }) + return + } + // get grant before increasing counter grant, err := auth.GetOAuth2GrantByID(ctx, token.GrantID) if err != nil || grant == nil { diff --git a/tests/integration/oauth_test.go b/tests/integration/oauth_test.go index 27c66f0e5a..3f14324cf7 100644 --- a/tests/integration/oauth_test.go +++ b/tests/integration/oauth_test.go @@ -455,6 +455,18 @@ func TestRefreshTokenInvalidation(t *testing.T) { assert.Equal(t, "unauthorized_client", string(parsedError.ErrorCode)) assert.Equal(t, "unable to parse refresh token", parsedError.ErrorDescription) + req = NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{ + "grant_type": "refresh_token", + "client_id": "da7da3ba-9a13-4167-856f-3899de0b0138", + "client_secret": "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=", + "redirect_uri": "a", + "refresh_token": parsed.AccessToken, + }) + resp = MakeRequest(t, req, http.StatusBadRequest) + require.NoError(t, json.Unmarshal(resp.Body.Bytes(), &parsedError)) + assert.Equal(t, "unauthorized_client", string(parsedError.ErrorCode)) + assert.Equal(t, "token is not a refresh token", parsedError.ErrorDescription) + req = NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{ "grant_type": "refresh_token", "client_id": "da7da3ba-9a13-4167-856f-3899de0b0138",