Skip to content

Commit a1e513b

Browse files
Kehrlannjgrandja
authored andcommitted
Throw invalid_grant when invalid token request with PKCE
Closes gh-581
1 parent 4d5b288 commit a1e513b

File tree

3 files changed

+23
-13
lines changed

3 files changed

+23
-13
lines changed

oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientAuthenticationProvider.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2021 the original author or authors.
2+
* Copyright 2020-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -228,7 +228,7 @@ private boolean authenticatePkceIfAvailable(OAuth2ClientAuthenticationToken clie
228228
(String) parameters.get(OAuth2ParameterNames.CODE),
229229
AUTHORIZATION_CODE_TOKEN_TYPE);
230230
if (authorization == null) {
231-
throwInvalidClient(OAuth2ParameterNames.CODE);
231+
throwInvalidGrant(OAuth2ParameterNames.CODE);
232232
}
233233

234234
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
@@ -238,7 +238,7 @@ private boolean authenticatePkceIfAvailable(OAuth2ClientAuthenticationToken clie
238238
.get(PkceParameterNames.CODE_CHALLENGE);
239239
if (!StringUtils.hasText(codeChallenge)) {
240240
if (registeredClient.getClientSettings().isRequireProofKey()) {
241-
throwInvalidClient(PkceParameterNames.CODE_CHALLENGE);
241+
throwInvalidGrant(PkceParameterNames.CODE_CHALLENGE);
242242
} else {
243243
return false;
244244
}
@@ -248,7 +248,7 @@ private boolean authenticatePkceIfAvailable(OAuth2ClientAuthenticationToken clie
248248
.get(PkceParameterNames.CODE_CHALLENGE_METHOD);
249249
String codeVerifier = (String) parameters.get(PkceParameterNames.CODE_VERIFIER);
250250
if (!codeVerifierValid(codeVerifier, codeChallenge, codeChallengeMethod)) {
251-
throwInvalidClient(PkceParameterNames.CODE_VERIFIER);
251+
throwInvalidGrant(PkceParameterNames.CODE_VERIFIER);
252252
}
253253

254254
return true;
@@ -291,10 +291,20 @@ private static void throwInvalidClient(String parameterName, Throwable cause) {
291291
throw new OAuth2AuthenticationException(error, error.toString(), cause);
292292
}
293293

294+
private static void throwInvalidGrant(String parameterName) {
295+
OAuth2Error error = new OAuth2Error(
296+
OAuth2ErrorCodes.INVALID_GRANT,
297+
"Client authentication failed: " + parameterName,
298+
null
299+
);
300+
throw new OAuth2AuthenticationException(error);
301+
}
302+
294303
private static class JwtClientAssertionDecoderFactory implements JwtDecoderFactory<RegisteredClient> {
295304
private static final String JWT_CLIENT_AUTHENTICATION_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc7523#section-3";
296305

297306
private static final Map<JwsAlgorithm, String> JCA_ALGORITHM_MAPPINGS;
307+
298308
static {
299309
Map<JwsAlgorithm, String> mappings = new HashMap<>();
300310
mappings.put(MacAlgorithm.HS256, "HmacSHA256");

oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2021 the original author or authors.
2+
* Copyright 2020-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -396,7 +396,7 @@ public void requestWhenPublicClientWithPkceThenReturnAccessTokenResponse() throw
396396
}
397397

398398
@Test
399-
public void requestWhenConfidentialClientWithPkceAndMissingCodeVerifierThenUnauthorized() throws Exception {
399+
public void requestWhenConfidentialClientWithPkceAndMissingCodeVerifierThenBadRequest() throws Exception {
400400
this.spring.register(AuthorizationServerConfiguration.class).autowire();
401401

402402
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
@@ -421,7 +421,7 @@ public void requestWhenConfidentialClientWithPkceAndMissingCodeVerifierThenUnaut
421421
.params(getTokenRequestParameters(registeredClient, authorizationCodeAuthorization))
422422
.param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId())
423423
.header(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(registeredClient)))
424-
.andExpect(status().isUnauthorized());
424+
.andExpect(status().isBadRequest());
425425
}
426426

427427
@Test

oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientAuthenticationProviderTests.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2021 the original author or authors.
2+
* Copyright 2020-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -279,7 +279,7 @@ public void authenticateWhenPkceAndInvalidCodeThenThrowOAuth2AuthenticationExcep
279279
.isInstanceOf(OAuth2AuthenticationException.class)
280280
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
281281
.satisfies(error -> {
282-
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
282+
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
283283
assertThat(error.getDescription()).contains(OAuth2ParameterNames.CODE);
284284
});
285285
}
@@ -305,7 +305,7 @@ public void authenticateWhenPkceAndPublicClientAndMissingCodeVerifierThenThrowOA
305305
.isInstanceOf(OAuth2AuthenticationException.class)
306306
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
307307
.satisfies(error -> {
308-
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
308+
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
309309
assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
310310
});
311311
}
@@ -331,7 +331,7 @@ public void authenticateWhenPkceAndConfidentialClientAndMissingCodeVerifierThenT
331331
.isInstanceOf(OAuth2AuthenticationException.class)
332332
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
333333
.satisfies(error -> {
334-
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
334+
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
335335
assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
336336
});
337337
}
@@ -357,7 +357,7 @@ public void authenticateWhenPkceAndPlainMethodAndInvalidCodeVerifierThenThrowOAu
357357
.isInstanceOf(OAuth2AuthenticationException.class)
358358
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
359359
.satisfies(error -> {
360-
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
360+
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
361361
assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
362362
});
363363
}
@@ -383,7 +383,7 @@ public void authenticateWhenPkceAndS256MethodAndInvalidCodeVerifierThenThrowOAut
383383
.isInstanceOf(OAuth2AuthenticationException.class)
384384
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
385385
.satisfies(error -> {
386-
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
386+
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_GRANT);
387387
assertThat(error.getDescription()).contains(PkceParameterNames.CODE_VERIFIER);
388388
});
389389
}

0 commit comments

Comments
 (0)