@@ -53,18 +53,24 @@ public async Task ChallengeWillTriggerRedirection()
53
53
using var server = host . GetTestServer ( ) ;
54
54
var transaction = await server . SendAsync ( "https://example.com/challenge" ) ;
55
55
Assert . Equal ( HttpStatusCode . Redirect , transaction . Response . StatusCode ) ;
56
- var location = transaction . Response . Headers . Location . ToString ( ) ;
57
- Assert . Contains ( "https://accounts.google.com/o/oauth2/v2/auth?response_type=code" , location ) ;
58
- Assert . Contains ( "&client_id=" , location ) ;
59
- Assert . Contains ( "&redirect_uri=" , location ) ;
60
- Assert . Contains ( "&scope=" , location ) ;
61
- Assert . Contains ( "&state=" , location ) ;
62
-
63
- Assert . DoesNotContain ( "access_type=" , location ) ;
64
- Assert . DoesNotContain ( "prompt=" , location ) ;
65
- Assert . DoesNotContain ( "approval_prompt=" , location ) ;
66
- Assert . DoesNotContain ( "login_hint=" , location ) ;
67
- Assert . DoesNotContain ( "include_granted_scopes=" , location ) ;
56
+ var location = transaction . Response . Headers . Location ;
57
+
58
+ Assert . StartsWith ( "https://accounts.google.com/o/oauth2/v2/auth?" , location . AbsoluteUri ) ;
59
+
60
+ var queryParams = QueryHelpers . ParseQuery ( location . Query ) ;
61
+ Assert . Equal ( "code" , queryParams [ "response_type" ] ) ;
62
+ Assert . Equal ( "Test Id" , queryParams [ "client_id" ] ) ;
63
+ Assert . True ( queryParams . ContainsKey ( "redirect_uri" ) ) ;
64
+ Assert . True ( queryParams . ContainsKey ( "scope" ) ) ;
65
+ Assert . True ( queryParams . ContainsKey ( "state" ) ) ;
66
+ Assert . True ( queryParams . ContainsKey ( "code_challenge" ) ) ;
67
+ Assert . Equal ( "S256" , queryParams [ "code_challenge_method" ] ) ;
68
+
69
+ Assert . False ( queryParams . ContainsKey ( "access_type" ) ) ;
70
+ Assert . False ( queryParams . ContainsKey ( "prompt" ) ) ;
71
+ Assert . False ( queryParams . ContainsKey ( "approval_prompt" ) ) ;
72
+ Assert . False ( queryParams . ContainsKey ( "login_hint" ) ) ;
73
+ Assert . False ( queryParams . ContainsKey ( "include_granted_scopes" ) ) ;
68
74
}
69
75
70
76
[ Fact ]
@@ -1010,6 +1016,75 @@ public async Task ChallengeGoogleWhenAlreadySignedWithGoogleSucceeds()
1010
1016
Assert . StartsWith ( "https://www.facebook.com/" , transaction . Response . Headers . Location . OriginalString ) ;
1011
1017
}
1012
1018
1019
+ [ Fact ]
1020
+ public async Task PkceSentToTokenEndpoint ( )
1021
+ {
1022
+ using var host = await CreateHost ( o =>
1023
+ {
1024
+ o . ClientId = "Test Client Id" ;
1025
+ o . ClientSecret = "Test Client Secret" ;
1026
+ o . BackchannelHttpHandler = new TestHttpMessageHandler
1027
+ {
1028
+ Sender = req =>
1029
+ {
1030
+ if ( req . RequestUri . AbsoluteUri == "https://oauth2.googleapis.com/token" )
1031
+ {
1032
+ var body = req . Content . ReadAsStringAsync ( ) . Result ;
1033
+ var form = new FormReader ( body ) ;
1034
+ var entries = form . ReadForm ( ) ;
1035
+ Assert . Equal ( "Test Client Id" , entries [ "client_id" ] ) ;
1036
+ Assert . Equal ( "https://example.com/signin-google" , entries [ "redirect_uri" ] ) ;
1037
+ Assert . Equal ( "Test Client Secret" , entries [ "client_secret" ] ) ;
1038
+ Assert . Equal ( "TestCode" , entries [ "code" ] ) ;
1039
+ Assert . Equal ( "authorization_code" , entries [ "grant_type" ] ) ;
1040
+ Assert . False ( string . IsNullOrEmpty ( entries [ "code_verifier" ] ) ) ;
1041
+
1042
+ return ReturnJsonResponse ( new
1043
+ {
1044
+ access_token = "Test Access Token" ,
1045
+ expire_in = 3600 ,
1046
+ token_type = "Bearer" ,
1047
+ } ) ;
1048
+ }
1049
+ else if ( req . RequestUri . GetComponents ( UriComponents . SchemeAndServer | UriComponents . Path , UriFormat . UriEscaped ) == "https://www.googleapis.com/oauth2/v3/userinfo" )
1050
+ {
1051
+ return ReturnJsonResponse ( new
1052
+ {
1053
+ id = "Test User ID" ,
1054
+ displayName = "Test Name" ,
1055
+ givenName = "Test Given Name" ,
1056
+ surname = "Test Family Name" ,
1057
+ mail = "Test email"
1058
+ } ) ;
1059
+ }
1060
+
1061
+ return null ;
1062
+ }
1063
+ } ;
1064
+ } ) ;
1065
+ using var server = host . GetTestServer ( ) ;
1066
+ var transaction = await server . SendAsync ( "https://example.com/challenge" ) ;
1067
+ Assert . Equal ( HttpStatusCode . Redirect , transaction . Response . StatusCode ) ;
1068
+ var locationUri = transaction . Response . Headers . Location ;
1069
+ Assert . StartsWith ( "https://accounts.google.com/o/oauth2/v2/auth" , locationUri . AbsoluteUri ) ;
1070
+
1071
+ var queryParams = QueryHelpers . ParseQuery ( locationUri . Query ) ;
1072
+ Assert . False ( string . IsNullOrEmpty ( queryParams [ "code_challenge" ] ) ) ;
1073
+ Assert . Equal ( "S256" , queryParams [ "code_challenge_method" ] ) ;
1074
+
1075
+ var nonceCookie = transaction . SetCookie . Single ( ) ;
1076
+ nonceCookie = nonceCookie . Substring ( 0 , nonceCookie . IndexOf ( ';' ) ) ;
1077
+
1078
+ transaction = await server . SendAsync (
1079
+ "https://example.com/signin-google?code=TestCode&state=" + queryParams [ "state" ] ,
1080
+ nonceCookie ) ;
1081
+ Assert . Equal ( HttpStatusCode . Redirect , transaction . Response . StatusCode ) ;
1082
+ Assert . Equal ( "/challenge" , transaction . Response . Headers . GetValues ( "Location" ) . First ( ) ) ;
1083
+ Assert . Equal ( 2 , transaction . SetCookie . Count ) ;
1084
+ Assert . StartsWith ( ".AspNetCore.Correlation." , transaction . SetCookie [ 0 ] ) ;
1085
+ Assert . StartsWith ( ".AspNetCore." + TestExtensions . CookieAuthenticationScheme , transaction . SetCookie [ 1 ] ) ;
1086
+ }
1087
+
1013
1088
private HttpMessageHandler CreateBackchannel ( )
1014
1089
{
1015
1090
return new TestHttpMessageHandler ( )
0 commit comments