@@ -127,39 +127,18 @@ public function respondToAccessTokenRequest(
127127 throw OAuthServerException::invalidRequest ('code ' , 'Cannot decrypt the authorization code ' , $ e );
128128 }
129129
130- // Validate code challenge
131- if (!empty ($ authCodePayload ->code_challenge )) {
132- $ codeVerifier = $ this ->getRequestParameter ('code_verifier ' , $ request , null );
133-
134- if ($ codeVerifier === null ) {
135- throw OAuthServerException::invalidRequest ('code_verifier ' );
136- }
130+ $ codeVerifier = $ this ->getRequestParameter ('code_verifier ' , $ request , null );
137131
138- // Validate code_verifier according to RFC-7636
139- // @see: https://tools.ietf.org/html/rfc7636#section-4.1
140- if (\preg_match ('/^[A-Za-z0-9-._~]{43,128}$/ ' , $ codeVerifier ) !== 1 ) {
141- throw OAuthServerException::invalidRequest (
142- 'code_verifier ' ,
143- 'Code Verifier must follow the specifications of RFC-7636. '
144- );
145- }
132+ // If a code challenge isn't present but a code verifier is, reject the request to block PKCE downgrade attack
133+ if (empty ($ authCodePayload ->code_challenge ) && $ codeVerifier !== null ) {
134+ throw OAuthServerException::invalidRequest (
135+ 'code_challenge ' ,
136+ 'code_verifier received when no code_challenge is present '
137+ );
138+ }
146139
147- if (\property_exists ($ authCodePayload , 'code_challenge_method ' )) {
148- if (isset ($ this ->codeChallengeVerifiers [$ authCodePayload ->code_challenge_method ])) {
149- $ codeChallengeVerifier = $ this ->codeChallengeVerifiers [$ authCodePayload ->code_challenge_method ];
150-
151- if ($ codeChallengeVerifier ->verifyCodeChallenge ($ codeVerifier , $ authCodePayload ->code_challenge ) === false ) {
152- throw OAuthServerException::invalidGrant ('Failed to verify `code_verifier`. ' );
153- }
154- } else {
155- throw OAuthServerException::serverError (
156- \sprintf (
157- 'Unsupported code challenge method `%s` ' ,
158- $ authCodePayload ->code_challenge_method
159- )
160- );
161- }
162- }
140+ if (!empty ($ authCodePayload ->code_challenge )) {
141+ $ this ->validateCodeChallenge ($ authCodePayload , $ codeVerifier );
163142 }
164143
165144 // Issue and persist new access token
@@ -181,6 +160,39 @@ public function respondToAccessTokenRequest(
181160 return $ responseType ;
182161 }
183162
163+ private function validateCodeChallenge ($ authCodePayload , $ codeVerifier )
164+ {
165+ if ($ codeVerifier === null ) {
166+ throw OAuthServerException::invalidRequest ('code_verifier ' );
167+ }
168+
169+ // Validate code_verifier according to RFC-7636
170+ // @see: https://tools.ietf.org/html/rfc7636#section-4.1
171+ if (\preg_match ('/^[A-Za-z0-9-._~]{43,128}$/ ' , $ codeVerifier ) !== 1 ) {
172+ throw OAuthServerException::invalidRequest (
173+ 'code_verifier ' ,
174+ 'Code Verifier must follow the specifications of RFC-7636. '
175+ );
176+ }
177+
178+ if (\property_exists ($ authCodePayload , 'code_challenge_method ' )) {
179+ if (isset ($ this ->codeChallengeVerifiers [$ authCodePayload ->code_challenge_method ])) {
180+ $ codeChallengeVerifier = $ this ->codeChallengeVerifiers [$ authCodePayload ->code_challenge_method ];
181+
182+ if ($ codeChallengeVerifier ->verifyCodeChallenge ($ codeVerifier , $ authCodePayload ->code_challenge ) === false ) {
183+ throw OAuthServerException::invalidGrant ('Failed to verify `code_verifier`. ' );
184+ }
185+ } else {
186+ throw OAuthServerException::serverError (
187+ \sprintf (
188+ 'Unsupported code challenge method `%s` ' ,
189+ $ authCodePayload ->code_challenge_method
190+ )
191+ );
192+ }
193+ }
194+ }
195+
184196 /**
185197 * Validate the authorization code.
186198 *
0 commit comments