[auth]: support oauth client_secret_basic / none / custom methods#720
[auth]: support oauth client_secret_basic / none / custom methods#720
Conversation
… during authorization code exchange.
… during refresh token exchange.
… refreshAuthorization to maintain compatibility.
… into ochafik/auth-merge-531-552
…ods' into ochafik/auth-merge-531-552
The applyBasicAuth function was incorrectly trying to set headers using array notation on a Headers object. Fixed by using the proper Headers.set() method instead of treating it as a plain object. This ensures that HTTP Basic authentication works correctly when client_secret_basic is the selected authentication method. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Thanks @ochafik ! This is looking pretty good. I'm experimenting with the branch right now, and have a suggested modification that I'll propose later tonight or tomorrow. |
SightStudio
left a comment
There was a problem hiding this comment.
I know my feedback came a bit late, but it looks good to me.
I don't have any major comments to add.
Thank you for reviewing it positively!
felixweinberger
left a comment
There was a problem hiding this comment.
only some nits, looks clean to me!
src/client/auth.test.ts
Outdated
| type OAuthClientProvider, | ||
| } from "./auth.js"; | ||
| import { OAuthMetadata } from 'src/shared/auth.js'; |
There was a problem hiding this comment.
nit: the project seems to use ../shared/auth.js as a pattern, i.e. relative imports (but I actually think this is better)
see discussion: https://anthropic.slack.com/archives/C0840HQ2Y2V/p1752075120212319
There was a problem hiding this comment.
Gone relative, thanks for the link
src/client/auth.ts
Outdated
| * @param url - The token endpoint URL being called | ||
| * @param headers - The request headers (can be modified to add authentication) | ||
| * @param params - The request body parameters (can be modified to add credentials) | ||
| */ |
There was a problem hiding this comment.
ultra-nit: @params are in a different order than the args
src/client/auth.ts
Outdated
| clientInformation: OAuthClientInformation, | ||
| supportedMethods: string[] | ||
| ): string { | ||
| const hasClientSecret = !!clientInformation.client_secret; |
There was a problem hiding this comment.
nit: we don't seem to use !! notation anywhere, maybe prefer explicitness?
const hasClientSecret = clientInformation.client_secret !== undefined && clientInformation.client_secret !== '';
There was a problem hiding this comment.
Tightened this / only testing against undefined
src/client/auth.ts
Outdated
| function selectClientAuthMethod( | ||
| clientInformation: OAuthClientInformation, | ||
| supportedMethods: string[] | ||
| ): string { |
There was a problem hiding this comment.
should this maybe return an enum?
enum ClientAuthMethod {
BASIC = "client_secret_basic",
POST = "client_secret_post",
NONE = "none"
}
src/client/auth.ts
Outdated
| if (method === "client_secret_basic") { | ||
| applyBasicAuth(client_id, client_secret, headers); | ||
| return; | ||
| } | ||
|
|
||
| if (method === "client_secret_post") { | ||
| applyPostAuth(client_id, client_secret, params); | ||
| return; | ||
| } | ||
|
|
||
| if (method === "none") { | ||
| applyPublicAuth(client_id, params); | ||
| return; | ||
| } |
There was a problem hiding this comment.
could make this a switch with the enum potentially
| if (addClientAuthentication) { | ||
| addClientAuthentication(headers, params, authorizationServerUrl, metadata); | ||
| } else { | ||
| // Determine and apply client authentication method | ||
| const supportedMethods = metadata?.token_endpoint_auth_methods_supported ?? []; | ||
| const authMethod = selectClientAuthMethod(clientInformation, supportedMethods); | ||
|
|
||
| applyClientAuthentication(authMethod, clientInformation, headers, params); |
| const body = request.body as URLSearchParams; | ||
| expect(body.get("client_id")).toBe("client123"); | ||
| expect(body.get("client_secret")).toBe("secret123"); | ||
| }); |
There was a problem hiding this comment.
should we have a test if it supports everything, that it chooses client_secret_basic
src/client/auth.test.ts
Outdated
| expect(body.get("client_id")).toBeNull(); // should not be in body | ||
| expect(body.get("client_secret")).toBeNull(); // should not be in body |
There was a problem hiding this comment.
nit: comments seem redundant
src/client/auth.test.ts
Outdated
| expect(body.get("client_id")).toBeNull(); // should not be in body | ||
| expect(body.get("client_secret")).toBeNull(); // should not be in body |
| const body = request.body as URLSearchParams; | ||
| expect(body.get("client_id")).toBe("client123"); | ||
| expect(body.get("client_secret")).toBe("secret123"); | ||
| }); |
src/client/auth.ts
Outdated
| * @param url - The token endpoint URL being called | ||
| * @param headers - The request headers (can be modified to add authentication) | ||
| * @param params - The request body parameters (can be modified to add credentials) | ||
| */ |
src/client/auth.ts
Outdated
| function selectClientAuthMethod( | ||
| clientInformation: OAuthClientInformation, | ||
| supportedMethods: string[] | ||
| ): string { |
src/client/auth.ts
Outdated
| clientInformation: OAuthClientInformation, | ||
| supportedMethods: string[] | ||
| ): string { | ||
| const hasClientSecret = !!clientInformation.client_secret; |
There was a problem hiding this comment.
Tightened this / only testing against undefined
src/client/auth.ts
Outdated
| if (method === "client_secret_basic") { | ||
| applyBasicAuth(client_id, client_secret, headers); | ||
| return; | ||
| } | ||
|
|
||
| if (method === "client_secret_post") { | ||
| applyPostAuth(client_id, client_secret, params); | ||
| return; | ||
| } | ||
|
|
||
| if (method === "none") { | ||
| applyPublicAuth(client_id, params); | ||
| return; | ||
| } |
src/client/auth.test.ts
Outdated
| type OAuthClientProvider, | ||
| } from "./auth.js"; | ||
| import { OAuthMetadata } from 'src/shared/auth.js'; |
There was a problem hiding this comment.
Gone relative, thanks for the link
|
Oh absolutely, fixed, thanks for bringing it up!
…On Thu, Jul 10, 2025 at 4:34 PM Dong Min Seol ***@***.***> wrote:
*SightStudio* left a comment (modelcontextprotocol/typescript-sdk#720)
<#720 (comment)>
https://github.com/modelcontextprotocol/typescript-sdk/releases/tag/1.15.1
@jerome3o-anthropic <https://github.com/jerome3o-anthropic>
It would be nice if co-authors could also be added to that list of
contributors.
--
--
Olivier
|
This is an attempt to merge #531 and #552
Motivation and Context
This merges two sets of OAuth changes:
OAuthClientProvider.addClientAuthenticationcallback (renamed from PR's proposedauthToTokenEndpoint) for custom auth methodsclient_secret_basic,none)How Has This Been Tested?
WIP: testing in inspector
Breaking Changes
n/a
Types of changes
Checklist
Additional context