nolint:bodyclose
(t *testing.T)
| 1126 | |
| 1127 | // nolint:bodyclose |
| 1128 | func TestMCPServerOAuth2PKCE(t *testing.T) { |
| 1129 | t.Parallel() |
| 1130 | |
| 1131 | t.Run("ConnectSetsPKCEParams", func(t *testing.T) { |
| 1132 | t.Parallel() |
| 1133 | |
| 1134 | ctx := testutil.Context(t, testutil.WaitLong) |
| 1135 | adminClient := newMCPClient(t) |
| 1136 | firstUser := coderdtest.CreateFirstUser(t, adminClient) |
| 1137 | memberClient, _ := coderdtest.CreateAnotherUser(t, adminClient, firstUser.OrganizationID) |
| 1138 | |
| 1139 | // Create an OAuth2 MCP server config. |
| 1140 | created, err := adminClient.CreateMCPServerConfig(ctx, codersdk.CreateMCPServerConfigRequest{ |
| 1141 | DisplayName: "PKCE Test", |
| 1142 | Slug: "pkce-test", |
| 1143 | Transport: "streamable_http", |
| 1144 | URL: "https://mcp.example.com/pkce", |
| 1145 | AuthType: "oauth2", |
| 1146 | OAuth2ClientID: "test-client", |
| 1147 | OAuth2AuthURL: "https://auth.example.com/authorize", |
| 1148 | OAuth2TokenURL: "https://auth.example.com/token", |
| 1149 | Availability: "default_on", |
| 1150 | Enabled: true, |
| 1151 | ToolAllowList: []string{}, |
| 1152 | ToolDenyList: []string{}, |
| 1153 | }) |
| 1154 | require.NoError(t, err) |
| 1155 | |
| 1156 | // Prevent the HTTP client from following redirects so we |
| 1157 | // can inspect the response headers and cookies directly. |
| 1158 | memberClient.HTTPClient.CheckRedirect = func(_ *http.Request, _ []*http.Request) error { |
| 1159 | return http.ErrUseLastResponse |
| 1160 | } |
| 1161 | |
| 1162 | connectURL, err := memberClient.URL.Parse( |
| 1163 | "/api/experimental/mcp/servers/" + created.ID.String() + "/oauth2/connect", |
| 1164 | ) |
| 1165 | require.NoError(t, err) |
| 1166 | |
| 1167 | req, err := http.NewRequestWithContext(ctx, "GET", connectURL.String(), nil) |
| 1168 | require.NoError(t, err) |
| 1169 | req.AddCookie(&http.Cookie{ |
| 1170 | Name: codersdk.SessionTokenCookie, |
| 1171 | Value: memberClient.SessionToken(), |
| 1172 | }) |
| 1173 | |
| 1174 | res, err := memberClient.HTTPClient.Do(req) |
| 1175 | require.NoError(t, err) |
| 1176 | defer res.Body.Close() |
| 1177 | |
| 1178 | require.Equal(t, http.StatusTemporaryRedirect, res.StatusCode) |
| 1179 | |
| 1180 | // The redirect URL must contain PKCE query parameters. |
| 1181 | location, err := res.Location() |
| 1182 | require.NoError(t, err) |
| 1183 | query := location.Query() |
| 1184 | require.Equal(t, "S256", query.Get("code_challenge_method"), |
| 1185 | "connect redirect must include code_challenge_method=S256") |
nothing calls this directly
no test coverage detected