-
Notifications
You must be signed in to change notification settings - Fork 6.1k
PKCE configuration - enabled by default #17507
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
PKCE configuration - enabled by default #17507
Conversation
Hi @jgrandja , Thank you for reviewing my pull request. I noticed that you marked it as "breaks passivity" and self-assigned the related issue. I want to understand this better so I can improve future contributions. Could you please clarify what aspect of the PR breaks passivity, and how you envision the correct approach? I'm eager to align with the design principles of the project and contribute effectively. Thanks again for your time and guidance! Best regards, |
Hi @rohan-naik07. I haven't had time to review your PR but I plan on it next week. Our process is to self-assign PR's when we review it and the user who submitted the PR is assigned the original issue. The reason I marked this "breaks-passivity" is because it is a breaking change that needs to be applied. For example, since the required change is for the OAuth2 Client to send PKCE parameters by default, it's possible that the authorization server does not support PKCE and therefore the flow will fail. So what was working previously might stop working with the upgrade to FYI, the reason for this change is OAuth 2.1 recommends/requires PKCE. |
Ok, that makes sense. Thanks for clarifying my doubts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR @rohan-naik07. Please see review comments.
Also, please rebase off of main
and ensure there is only 1 commit with the changes. Thanks.
clientRegistration.clientName = StringUtils.hasText(this.clientName) ? this.clientName | ||
: this.registrationId; | ||
clientRegistration.clientSettings = this.clientSettings; | ||
if (this.clientSettings.requireProofKey) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove this since clientRegistration.clientSettings
is set in previous line with this.clientSettings
and only the clientSettings
should be used.
private ClientSettings() { | ||
|
||
} | ||
private ClientSettings() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please revert this formatting change as only required changes should be applied
private boolean requireProofKey; | ||
|
||
private Builder() { | ||
this.requireProofKey = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this to variable initialization private boolean requireProofKey = true;
} | ||
if (ClientAuthenticationMethod.NONE.equals(clientRegistration.getClientAuthenticationMethod()) | ||
|| clientRegistration.getClientSettings().isRequireProofKey()) { | ||
if (clientRegistration.getClientSettings().isRequireProofKey()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Public Clients (indicated with ClientAuthenticationMethod.NONE
) always require PKCE but with this change it's possible to disable PKCE for Public Clients. Please revert this as the original logic is still correct.
} | ||
if (ClientAuthenticationMethod.NONE.equals(clientRegistration.getClientAuthenticationMethod()) | ||
|| clientRegistration.getClientSettings().isRequireProofKey()) { | ||
if (clientRegistration.getClientSettings().isRequireProofKey()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Public Clients (indicated with ClientAuthenticationMethod.NONE
) always require PKCE but with this change it's possible to disable PKCE for Public Clients. Please revert this as the original logic is still correct.
==== | ||
Public Clients are supported using https://tools.ietf.org/html/rfc7636[Proof Key for Code Exchange] (PKCE). | ||
PKCE will automatically be used when `client-authentication-method` is set to "none" (`ClientAuthenticationMethod.NONE`). | ||
https://tools.ietf.org/html/rfc7636[Proof Key for Code Exchange] (PKCE) will be enabled by default for public as well as confidential clients. Refer https://docs.spring.io/spring-security/reference/servlet/oauth2/client/client-authentication.html#oauth2-client-authentication-public[this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please revert this as the original content is still valid
The supported values are *header*, *form*, and *query*. | ||
<16> `userNameAttributeName`: The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user. | ||
<17> [[oauth2Client-client-registration-requireProofKey]]`requireProofKey`: If `true` or if `authorizationGrantType` is `none`, then PKCE will be enabled by default. | ||
<17> [[oauth2Client-client-registration-requireProofKey]]`requireProofKey`: This will by default be `true`, as PKCE will be enabled by default. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update the text to:
If true
or if clientAuthenticationMethod
is none
, then PKCE will be enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't we stressing enough on the point that PKCE will be also enabled for confidential clients?... Or we don't want to for now
// @formatter:on | ||
} | ||
|
||
public static ClientRegistration.Builder publicClientRegistrationWithNoPkce() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove this as TestClientRegistrations.clientRegistration()
can be used and the caller can simply change builder.clientSettings(updatedClientSettings)
abe7742
to
cb7cff4
Compare
80416c4
to
4f7a21c
Compare
Hi @jgrandja , just wanted to kindly follow up on this PR. Please let me know if there are any changes or clarifications I can make to help move it forward. |
Hi @rohan-naik07. Really apologize for the delay. I was at SpringOne last week and I was very busy leading up to that. I have a little more breathing room now and need to catch up on quite a bit. I'm planning on reviewing your PR later this week or early next week. Thanks for your patience. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your patience @rohan-naik07. Please see review comments.
I noticed there were a lot of changes made that were not relevant to the enhancement this PR addresses, especially in DefaultOAuth2AuthorizationRequestResolverTests
.
In general, PR's should only add/update the minimal amount of code necessary to fulfill the enhancement requirements. No other code should change, especially if it's not relevant to the enhancement.
I would recommend going through all the code again and reverting everything that is not needed as part of this enhancement. There is quite a bit of updates in DefaultOAuth2AuthorizationRequestResolverTests
that should be reverted.
Thanks.
The supported values are *header*, *form*, and *query*. | ||
<16> `userNameAttributeName`: The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user. | ||
<17> [[oauth2Client-client-registration-requireProofKey]]`requireProofKey`: If `true` or if `authorizationGrantType` is `none`, then PKCE will be enabled by default. | ||
<17> [[oauth2Client-client-registration-requireProofKey]]`requireProofKey`: If `true` or if `authorizationGrantType` is `none`, then PKCE will be enabled. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in this comment, please update to:
If true
or if clientAuthenticationMethod
is none
, then PKCE will be enabled.
clientRegistration.clientName = StringUtils.hasText(this.clientName) ? this.clientName | ||
: this.registrationId; | ||
clientRegistration.clientSettings = this.clientSettings; | ||
if (clientRegistration.clientSettings.requireProofKey) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not understanding the reason for this but I believe it should be removed.
"AuthorizationGrantType: %s does not match the pre-defined constant %s and won't match a valid OAuth2AuthorizedClientProvider", | ||
this.authorizationGrantType, authorizationGrantType)); | ||
} | ||
if (!AuthorizationGrantType.AUTHORIZATION_CODE.equals(this.authorizationGrantType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add a new validation check as follows:
If authorization_code
and client_authentication_method
equals none
then pkce must be true
else invalid
private static final long serialVersionUID = 7495627155437124692L; | ||
|
||
private boolean requireProofKey; | ||
private boolean requireProofKey = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be reverted since it will be set by the Builder
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; | ||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException; | ||
import static org.assertj.core.api.Assertions.*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please revert this as wildcard imports are not allowed
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright 2004-present the original author or authors. | |||
* Copyright 2002-2025 the original author or authors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not change. Please revert.
} | ||
|
||
@Test | ||
void authorizationRequestBaseUriEqualToRedirectFilter() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this removed? Please revert.
public void resolveWhenNotAuthorizationRequestThenDoesNotResolve() { | ||
String requestUri = "/path"; | ||
MockHttpServletRequest request = get(requestUri).build(); | ||
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did this change? Please only make required changes that are needed. Please revert.
public void resolveWhenNotAuthorizationRequestThenRequestBodyNotConsumed() throws IOException { | ||
String requestUri = "/path"; | ||
MockHttpServletRequest request = post(requestUri).build(); | ||
MockHttpServletRequest request = new MockHttpServletRequest("POST", requestUri); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did this change? Please only make required changes that are needed. Please revert.
assertPkceApplied(authorizationRequest, clientRegistration); | ||
} | ||
|
||
// gh-6548 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this removed? The comment gh-6548
typically (by convention) refers to a bug that was fixed previously so I don't think it should be removed.
4f7a21c
to
d3b143d
Compare
5dd2b47
to
a3020f9
Compare
Signed-off-by: Rohan Naik <[email protected]>
a3020f9
to
5efddb4
Compare
Fixes gh-16391
PKCE enabled by default for confidential as well as public clients.
Client Authentication method won't affect the PKCE customizer.
PKCE can be disabled using isRequireProofKey() client setting.