-
Notifications
You must be signed in to change notification settings - Fork 1k
[auth]: support oauth client_secret_basic / none / custom methods #720
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ultra-nit: @params
are in a different order than the args
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooops, fixed
src/client/auth.ts
Outdated
clientInformation: OAuthClientInformation, | ||
supportedMethods: string[] | ||
): string { | ||
const hasClientSecret = !!clientInformation.client_secret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this maybe return an enum?
enum ClientAuthMethod {
BASIC = "client_secret_basic",
POST = "client_secret_post",
NONE = "none"
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could make this a switch with the enum potentially
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we have a test if it supports everything, that it chooses client_secret_basic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, added!
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: comments seem redundant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Felix!
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, added!
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooops, fixed
src/client/auth.ts
Outdated
function selectClientAuthMethod( | ||
clientInformation: OAuthClientInformation, | ||
supportedMethods: string[] | ||
): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
src/client/auth.ts
Outdated
clientInformation: OAuthClientInformation, | ||
supportedMethods: string[] | ||
): string { | ||
const hasClientSecret = !!clientInformation.client_secret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.addClientAuthentication
callback (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