spring-projects / spring-authorization-server

Spring Authorization Server
https://spring.io/projects/spring-authorization-server
Apache License 2.0
4.78k stars 1.25k forks source link

Fix PKCE: Token endpoint return 401 error when isRequireProofKey is false #1640

Closed loren-coding closed 2 weeks ago

loren-coding commented 3 weeks ago

Describe the bug Token Endpoint return 401error when isRequireProofKeyis false

To Reproduce Steps to reproduce the behavior.

  1. Configure the PKCE client and set isRequireProofKey to false

    spring:
    oauth2:
      authorizationserver:
        client:
          public-client:
            registration:
              client-id: "public-client"
              client-authentication-methods:
                - "none"
              authorization-grant-types:
                - "authorization_code"
                - "refresh_token"
              redirect-uris:
                - "http://127.0.0.1:8080/authorized"
              scopes:
                - "openid"
                - "profile"
            requireProofKey: false
  2. Authorization endpoint and get code .
    5KGQuCD9VU-X8jw2hpiTRy74HLt8UxBtBbj4TmmUm63URJKxXAjK3f8iX2Pfrds8bcgWaACM3RM6p0q7_dXRO6QuEyxEXE66FfwYI63FT5EyQRjvKtfo0JC-eN0G4Ecx http://localhost:9000/oauth2/authorize?response_type=code&client_id=public-client&redirect_uri=http://127.0.0.1:8080/authorized&state=123&scope=openid%20profile

  3. OAuth2 Token Endpoint

    curl -i --request POST \
    --url http://localhost:9000/oauth2/token \
    --header 'content-type: application/x-www-form-urlencoded' \
    --data grant_type=authorization_code \
    --data code=5KGQuCD9VU-X8jw2hpiTRy74HLt8UxBtBbj4TmmUm63URJKxXAjK3f8iX2Pfrds8bcgWaACM3RM6p0q7_dXRO6QuEyxEXE66FfwYI63FT5EyQRjvKtfo0JC-eN0G4Ecx \
    --data 'redirect_uri="http://127.0.0.1:8080/authorized"' \
    --data state=123 \
    --data client_id=pub-client
    ########### 401 ERROR ###########
    HTTP/1.1 401
    Vary: Origin
    Vary: Access-Control-Request-Method
    Vary: Access-Control-Request-Headers
    X-Content-Type-Options: nosniff
    X-XSS-Protection: 0
    Cache-Control: no-cache, no-store, max-age=0, must-revalidate
    Pragma: no-cache
    Expires: 0
    X-Frame-Options: DENY
    Content-Length: 0
    Date: Thu, 13 Jun 2024 04:03:35 GMT

Caused by OAuth2ClientAuthenticationFilter : PublicClientAuthenticationConverter : OAuth2EndpointUtils.matchesPkceTokenRequest(request) required code_verifier . in addition, The ClientSettings#requireProofKey is invalid image

PublicClientAuthenticationProvider: CodeVerifierAuthenticator image

Expected behavior Return token normally.

jgrandja commented 2 weeks ago

@loren-coding Public clients MUST authenticate at the Token Endpoint using the code_verifier parameter.

Please review the PKCE spec as the client also needs to send the code_challenge parameter in the Authorization Request.

Also see the following integration test to understand the flow

https://github.com/spring-projects/spring-authorization-server/blob/314a41b321ab77f6e9a8b479fd49566718e89784/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2AuthorizationCodeGrantTests.java#L414

loren-coding commented 2 weeks ago

@loren-coding Public clients MUST authenticate at the Token Endpoint using the code_verifier parameter.

Please review the PKCE spec as the client also needs to send the code_challenge parameter in the Authorization Request.

Also see the following integration test to understand the flow

https://github.com/spring-projects/spring-authorization-server/blob/314a41b321ab77f6e9a8b479fd49566718e89784/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2AuthorizationCodeGrantTests.java#L414

I understand that this violates the PKCE protocol. Is the existing configuration ClientSettings#requireProofKey invalid? What is the purpose of the ClientSettings#requireProofKey configuration? confuses me

jgrandja commented 2 weeks ago

@loren-coding PKCE is required for Public Clients but it is not for Confidential Clients. However, you could enforce PKCE for Confidential Clients by setting ClientSettings#requireProofKey for increased security.

loren-coding commented 2 weeks ago

@loren-coding PKCE is required for Public Clients but it is not for Confidential Clients. However, you could enforce PKCE for Confidential Clients by setting ClientSettings#requireProofKey for increased security.

Got it, thank you very much for your explanation