@@ -213,5 +213,40 @@ private string GetRSA2Signature([NotNull] SortedDictionary<string, string> sorte
213
213
214
214
return Convert . ToBase64String ( encryptedBytes ) ;
215
215
}
216
+
217
+ /// <inheritdoc />
218
+ protected override string BuildChallengeUrl ( AuthenticationProperties properties , string redirectUri )
219
+ {
220
+ var scopeParameter = properties . GetParameter < ICollection < string > > ( OAuthChallengeProperties . ScopeKey ) ;
221
+ var scope = scopeParameter != null ? FormatScope ( scopeParameter ) : FormatScope ( ) ;
222
+
223
+ var parameters = new Dictionary < string , string >
224
+ {
225
+ [ "app_id" ] = Options . ClientId , // Used instead of "client_id"
226
+ [ "scope" ] = scope ,
227
+ [ "response_type" ] = "code" ,
228
+ [ "redirect_uri" ] = redirectUri ,
229
+ } ;
230
+
231
+ if ( Options . UsePkce )
232
+ {
233
+ var bytes = new byte [ 32 ] ;
234
+ RandomNumberGenerator . Fill ( bytes ) ;
235
+ var codeVerifier = Microsoft . AspNetCore . Authentication . Base64UrlTextEncoder . Encode ( bytes ) ;
236
+
237
+ // Store this for use during the code redemption.
238
+ properties . Items . Add ( OAuthConstants . CodeVerifierKey , codeVerifier ) ;
239
+
240
+ var challengeBytes = SHA256 . HashData ( Encoding . UTF8 . GetBytes ( codeVerifier ) ) ;
241
+ var codeChallenge = WebEncoders . Base64UrlEncode ( challengeBytes ) ;
242
+
243
+ parameters [ OAuthConstants . CodeChallengeKey ] = codeChallenge ;
244
+ parameters [ OAuthConstants . CodeChallengeMethodKey ] = OAuthConstants . CodeChallengeMethodS256 ;
245
+ }
246
+
247
+ parameters [ "state" ] = Options . StateDataFormat . Protect ( properties ) ;
248
+
249
+ return QueryHelpers . AddQueryString ( Options . AuthorizationEndpoint , parameters ! ) ;
250
+ }
216
251
}
217
252
}
0 commit comments