Skip to content

Commit 065d235

Browse files
committed
rebase after prettier update
1 parent e74a358 commit 065d235

File tree

5 files changed

+53
-22
lines changed

5 files changed

+53
-22
lines changed

src/client/auth.test.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,7 +1588,8 @@ describe('OAuth Authorization', () => {
15881588
// Mock provider methods for authorization flow
15891589
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
15901590
client_id: 'test-client',
1591-
client_secret: 'test-secret'
1591+
client_secret: 'test-secret',
1592+
redirect_uris: ['http://localhost:3000/callback']
15921593
});
15931594
(mockProvider.tokens as jest.Mock).mockResolvedValue(undefined);
15941595
(mockProvider.saveCodeVerifier as jest.Mock).mockResolvedValue(undefined);
@@ -1658,7 +1659,8 @@ describe('OAuth Authorization', () => {
16581659
// Mock provider methods for token exchange
16591660
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
16601661
client_id: 'test-client',
1661-
client_secret: 'test-secret'
1662+
client_secret: 'test-secret',
1663+
redirect_uris: ['http://localhost:3000/callback']
16621664
});
16631665
(mockProvider.codeVerifier as jest.Mock).mockResolvedValue('test-verifier');
16641666
(mockProvider.saveTokens as jest.Mock).mockResolvedValue(undefined);
@@ -1724,7 +1726,8 @@ describe('OAuth Authorization', () => {
17241726
// Mock provider methods for token refresh
17251727
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
17261728
client_id: 'test-client',
1727-
client_secret: 'test-secret'
1729+
client_secret: 'test-secret',
1730+
redirect_uris: ['http://localhost:3000/callback']
17281731
});
17291732
(mockProvider.tokens as jest.Mock).mockResolvedValue({
17301733
access_token: 'old-access',
@@ -1790,7 +1793,8 @@ describe('OAuth Authorization', () => {
17901793
// Mock provider methods
17911794
(providerWithCustomValidation.clientInformation as jest.Mock).mockResolvedValue({
17921795
client_id: 'test-client',
1793-
client_secret: 'test-secret'
1796+
client_secret: 'test-secret',
1797+
redirect_uris: ['http://localhost:3000/callback']
17941798
});
17951799
(providerWithCustomValidation.tokens as jest.Mock).mockResolvedValue(undefined);
17961800
(providerWithCustomValidation.saveCodeVerifier as jest.Mock).mockResolvedValue(undefined);
@@ -1845,7 +1849,8 @@ describe('OAuth Authorization', () => {
18451849
// Mock provider methods
18461850
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
18471851
client_id: 'test-client',
1848-
client_secret: 'test-secret'
1852+
client_secret: 'test-secret',
1853+
redirect_uris: ['http://localhost:3000/callback']
18491854
});
18501855
(mockProvider.tokens as jest.Mock).mockResolvedValue(undefined);
18511856
(mockProvider.saveCodeVerifier as jest.Mock).mockResolvedValue(undefined);
@@ -1903,7 +1908,8 @@ describe('OAuth Authorization', () => {
19031908
// Mock provider methods
19041909
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
19051910
client_id: 'test-client',
1906-
client_secret: 'test-secret'
1911+
client_secret: 'test-secret',
1912+
redirect_uris: ['http://localhost:3000/callback']
19071913
});
19081914
(mockProvider.tokens as jest.Mock).mockResolvedValue(undefined);
19091915
(mockProvider.saveCodeVerifier as jest.Mock).mockResolvedValue(undefined);
@@ -1970,7 +1976,8 @@ describe('OAuth Authorization', () => {
19701976
// Mock provider methods for token exchange
19711977
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
19721978
client_id: 'test-client',
1973-
client_secret: 'test-secret'
1979+
client_secret: 'test-secret',
1980+
redirect_uris: ['http://localhost:3000/callback']
19741981
});
19751982
(mockProvider.codeVerifier as jest.Mock).mockResolvedValue('test-verifier');
19761983
(mockProvider.saveTokens as jest.Mock).mockResolvedValue(undefined);
@@ -2033,7 +2040,8 @@ describe('OAuth Authorization', () => {
20332040
// Mock provider methods for token refresh
20342041
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
20352042
client_id: 'test-client',
2036-
client_secret: 'test-secret'
2043+
client_secret: 'test-secret',
2044+
redirect_uris: ['http://localhost:3000/callback']
20372045
});
20382046
(mockProvider.tokens as jest.Mock).mockResolvedValue({
20392047
access_token: 'old-access',
@@ -2094,7 +2102,8 @@ describe('OAuth Authorization', () => {
20942102
// Mock provider methods
20952103
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
20962104
client_id: 'test-client',
2097-
client_secret: 'test-secret'
2105+
client_secret: 'test-secret',
2106+
redirect_uris: ['http://localhost:3000/callback']
20982107
});
20992108
(mockProvider.tokens as jest.Mock).mockResolvedValue(undefined);
21002109
(mockProvider.saveCodeVerifier as jest.Mock).mockResolvedValue(undefined);
@@ -2156,7 +2165,8 @@ describe('OAuth Authorization', () => {
21562165
},
21572166
clientInformation: jest.fn().mockResolvedValue({
21582167
client_id: 'client123',
2159-
client_secret: 'secret123'
2168+
client_secret: 'secret123',
2169+
redirect_uris: ['http://localhost:3000/callback']
21602170
}),
21612171
tokens: jest.fn().mockResolvedValue(undefined),
21622172
saveTokens: jest.fn(),

src/client/auth.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import pkceChallenge from 'pkce-challenge';
22
import { LATEST_PROTOCOL_VERSION } from '../types.js';
33
import {
44
OAuthClientMetadata,
5-
OAuthClientInformation,
65
OAuthTokens,
76
OAuthMetadata,
87
OAuthClientInformationFull,
@@ -56,7 +55,7 @@ export interface OAuthClientProvider {
5655
* server, or returns `undefined` if the client is not registered with the
5756
* server.
5857
*/
59-
clientInformation(): OAuthClientInformation | undefined | Promise<OAuthClientInformation | undefined>;
58+
clientInformation(): OAuthClientInformationFull | undefined | Promise<OAuthClientInformationFull | undefined>;
6059

6160
/**
6261
* If implemented, this permits the OAuth client to dynamically register with
@@ -149,6 +148,10 @@ export class UnauthorizedError extends Error {
149148

150149
type ClientAuthMethod = 'client_secret_basic' | 'client_secret_post' | 'none';
151150

151+
function isClientAuthMethod(method: string): method is ClientAuthMethod {
152+
return ['client_secret_basic', 'client_secret_post', 'none'].includes(method);
153+
}
154+
152155
const AUTHORIZATION_CODE_RESPONSE_TYPE = 'code';
153156
const AUTHORIZATION_CODE_CHALLENGE_METHOD = 'S256';
154157

@@ -164,14 +167,23 @@ const AUTHORIZATION_CODE_CHALLENGE_METHOD = 'S256';
164167
* @param supportedMethods - Authentication methods supported by the authorization server
165168
* @returns The selected authentication method
166169
*/
167-
function selectClientAuthMethod(clientInformation: OAuthClientInformation, supportedMethods: string[]): ClientAuthMethod {
170+
function selectClientAuthMethod(clientInformation: OAuthClientInformationFull, supportedMethods: string[]): ClientAuthMethod {
168171
const hasClientSecret = clientInformation.client_secret !== undefined;
169172

170173
// If server doesn't specify supported methods, use RFC 6749 defaults
171174
if (supportedMethods.length === 0) {
172175
return hasClientSecret ? 'client_secret_post' : 'none';
173176
}
174177

178+
// Prefer the method returned by the server during client registration if valid and supported
179+
if (
180+
clientInformation.token_endpoint_auth_method &&
181+
isClientAuthMethod(clientInformation.token_endpoint_auth_method) &&
182+
supportedMethods.includes(clientInformation.token_endpoint_auth_method)
183+
) {
184+
return clientInformation.token_endpoint_auth_method;
185+
}
186+
175187
// Try methods in priority order (most secure first)
176188
if (hasClientSecret && supportedMethods.includes('client_secret_basic')) {
177189
return 'client_secret_basic';
@@ -205,7 +217,7 @@ function selectClientAuthMethod(clientInformation: OAuthClientInformation, suppo
205217
*/
206218
function applyClientAuthentication(
207219
method: ClientAuthMethod,
208-
clientInformation: OAuthClientInformation,
220+
clientInformation: OAuthClientInformationFull,
209221
headers: Headers,
210222
params: URLSearchParams
211223
): void {
@@ -793,7 +805,7 @@ export async function startAuthorization(
793805
resource
794806
}: {
795807
metadata?: AuthorizationServerMetadata;
796-
clientInformation: OAuthClientInformation;
808+
clientInformation: OAuthClientInformationFull;
797809
redirectUrl: string | URL;
798810
scope?: string;
799811
state?: string;
@@ -876,7 +888,7 @@ export async function exchangeAuthorization(
876888
fetchFn
877889
}: {
878890
metadata?: AuthorizationServerMetadata;
879-
clientInformation: OAuthClientInformation;
891+
clientInformation: OAuthClientInformationFull;
880892
authorizationCode: string;
881893
codeVerifier: string;
882894
redirectUri: string | URL;
@@ -955,7 +967,7 @@ export async function refreshAuthorization(
955967
fetchFn
956968
}: {
957969
metadata?: AuthorizationServerMetadata;
958-
clientInformation: OAuthClientInformation;
970+
clientInformation: OAuthClientInformationFull;
959971
refreshToken: string;
960972
resource?: URL;
961973
addClientAuthentication?: OAuthClientProvider['addClientAuthentication'];

src/client/sse.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,11 @@ describe('SSEClientTransport', () => {
355355
get clientMetadata() {
356356
return { redirect_uris: ['http://localhost/callback'] };
357357
},
358-
clientInformation: jest.fn(() => ({ client_id: 'test-client-id', client_secret: 'test-client-secret' })),
358+
clientInformation: jest.fn(() => ({
359+
client_id: 'test-client-id',
360+
client_secret: 'test-client-secret',
361+
redirect_uris: ['http://localhost/callback']
362+
})),
359363
tokens: jest.fn(),
360364
saveTokens: jest.fn(),
361365
redirectToAuthorization: jest.fn(),
@@ -1159,7 +1163,8 @@ describe('SSEClientTransport', () => {
11591163
const clientInfo = config.clientRegistered
11601164
? {
11611165
client_id: 'test-client-id',
1162-
client_secret: 'test-client-secret'
1166+
client_secret: 'test-client-secret',
1167+
redirect_uris: ['http://localhost/callback']
11631168
}
11641169
: undefined;
11651170

src/client/streamableHttp.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ describe('StreamableHTTPClientTransport', () => {
1515
get clientMetadata() {
1616
return { redirect_uris: ['http://localhost/callback'] };
1717
},
18-
clientInformation: jest.fn(() => ({ client_id: 'test-client-id', client_secret: 'test-client-secret' })),
18+
clientInformation: jest.fn(() => ({
19+
client_id: 'test-client-id',
20+
client_secret: 'test-client-secret',
21+
redirect_uris: ['http://localhost/callback']
22+
})),
1923
tokens: jest.fn(),
2024
saveTokens: jest.fn(),
2125
redirectToAuthorization: jest.fn(),

src/examples/client/simpleOAuthClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { URL } from 'node:url';
66
import { exec } from 'node:child_process';
77
import { Client } from '../../client/index.js';
88
import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js';
9-
import { OAuthClientInformation, OAuthClientInformationFull, OAuthClientMetadata, OAuthTokens } from '../../shared/auth.js';
9+
import { OAuthClientInformationFull, OAuthClientMetadata, OAuthTokens } from '../../shared/auth.js';
1010
import { CallToolRequest, ListToolsRequest, CallToolResultSchema, ListToolsResultSchema } from '../../types.js';
1111
import { OAuthClientProvider, UnauthorizedError } from '../../client/auth.js';
1212

@@ -46,7 +46,7 @@ class InMemoryOAuthClientProvider implements OAuthClientProvider {
4646
return this._clientMetadata;
4747
}
4848

49-
clientInformation(): OAuthClientInformation | undefined {
49+
clientInformation(): OAuthClientInformationFull | undefined {
5050
return this._clientInformation;
5151
}
5252

0 commit comments

Comments
 (0)