Skip to content

Commit 110b067

Browse files
committed
rebase after prettier update
1 parent c84ef24 commit 110b067

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
@@ -1587,7 +1587,8 @@ describe('OAuth Authorization', () => {
15871587
// Mock provider methods for authorization flow
15881588
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
15891589
client_id: 'test-client',
1590-
client_secret: 'test-secret'
1590+
client_secret: 'test-secret',
1591+
redirect_uris: ['http://localhost:3000/callback']
15911592
});
15921593
(mockProvider.tokens as jest.Mock).mockResolvedValue(undefined);
15931594
(mockProvider.saveCodeVerifier as jest.Mock).mockResolvedValue(undefined);
@@ -1657,7 +1658,8 @@ describe('OAuth Authorization', () => {
16571658
// Mock provider methods for token exchange
16581659
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
16591660
client_id: 'test-client',
1660-
client_secret: 'test-secret'
1661+
client_secret: 'test-secret',
1662+
redirect_uris: ['http://localhost:3000/callback']
16611663
});
16621664
(mockProvider.codeVerifier as jest.Mock).mockResolvedValue('test-verifier');
16631665
(mockProvider.saveTokens as jest.Mock).mockResolvedValue(undefined);
@@ -1723,7 +1725,8 @@ describe('OAuth Authorization', () => {
17231725
// Mock provider methods for token refresh
17241726
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
17251727
client_id: 'test-client',
1726-
client_secret: 'test-secret'
1728+
client_secret: 'test-secret',
1729+
redirect_uris: ['http://localhost:3000/callback']
17271730
});
17281731
(mockProvider.tokens as jest.Mock).mockResolvedValue({
17291732
access_token: 'old-access',
@@ -1789,7 +1792,8 @@ describe('OAuth Authorization', () => {
17891792
// Mock provider methods
17901793
(providerWithCustomValidation.clientInformation as jest.Mock).mockResolvedValue({
17911794
client_id: 'test-client',
1792-
client_secret: 'test-secret'
1795+
client_secret: 'test-secret',
1796+
redirect_uris: ['http://localhost:3000/callback']
17931797
});
17941798
(providerWithCustomValidation.tokens as jest.Mock).mockResolvedValue(undefined);
17951799
(providerWithCustomValidation.saveCodeVerifier as jest.Mock).mockResolvedValue(undefined);
@@ -1844,7 +1848,8 @@ describe('OAuth Authorization', () => {
18441848
// Mock provider methods
18451849
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
18461850
client_id: 'test-client',
1847-
client_secret: 'test-secret'
1851+
client_secret: 'test-secret',
1852+
redirect_uris: ['http://localhost:3000/callback']
18481853
});
18491854
(mockProvider.tokens as jest.Mock).mockResolvedValue(undefined);
18501855
(mockProvider.saveCodeVerifier as jest.Mock).mockResolvedValue(undefined);
@@ -1902,7 +1907,8 @@ describe('OAuth Authorization', () => {
19021907
// Mock provider methods
19031908
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
19041909
client_id: 'test-client',
1905-
client_secret: 'test-secret'
1910+
client_secret: 'test-secret',
1911+
redirect_uris: ['http://localhost:3000/callback']
19061912
});
19071913
(mockProvider.tokens as jest.Mock).mockResolvedValue(undefined);
19081914
(mockProvider.saveCodeVerifier as jest.Mock).mockResolvedValue(undefined);
@@ -1969,7 +1975,8 @@ describe('OAuth Authorization', () => {
19691975
// Mock provider methods for token exchange
19701976
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
19711977
client_id: 'test-client',
1972-
client_secret: 'test-secret'
1978+
client_secret: 'test-secret',
1979+
redirect_uris: ['http://localhost:3000/callback']
19731980
});
19741981
(mockProvider.codeVerifier as jest.Mock).mockResolvedValue('test-verifier');
19751982
(mockProvider.saveTokens as jest.Mock).mockResolvedValue(undefined);
@@ -2032,7 +2039,8 @@ describe('OAuth Authorization', () => {
20322039
// Mock provider methods for token refresh
20332040
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
20342041
client_id: 'test-client',
2035-
client_secret: 'test-secret'
2042+
client_secret: 'test-secret',
2043+
redirect_uris: ['http://localhost:3000/callback']
20362044
});
20372045
(mockProvider.tokens as jest.Mock).mockResolvedValue({
20382046
access_token: 'old-access',
@@ -2093,7 +2101,8 @@ describe('OAuth Authorization', () => {
20932101
// Mock provider methods
20942102
(mockProvider.clientInformation as jest.Mock).mockResolvedValue({
20952103
client_id: 'test-client',
2096-
client_secret: 'test-secret'
2104+
client_secret: 'test-secret',
2105+
redirect_uris: ['http://localhost:3000/callback']
20972106
});
20982107
(mockProvider.tokens as jest.Mock).mockResolvedValue(undefined);
20992108
(mockProvider.saveCodeVerifier as jest.Mock).mockResolvedValue(undefined);
@@ -2155,7 +2164,8 @@ describe('OAuth Authorization', () => {
21552164
},
21562165
clientInformation: jest.fn().mockResolvedValue({
21572166
client_id: 'client123',
2158-
client_secret: 'secret123'
2167+
client_secret: 'secret123',
2168+
redirect_uris: ['http://localhost:3000/callback']
21592169
}),
21602170
tokens: jest.fn().mockResolvedValue(undefined),
21612171
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 {
@@ -790,7 +802,7 @@ export async function startAuthorization(
790802
resource
791803
}: {
792804
metadata?: AuthorizationServerMetadata;
793-
clientInformation: OAuthClientInformation;
805+
clientInformation: OAuthClientInformationFull;
794806
redirectUrl: string | URL;
795807
scope?: string;
796808
state?: string;
@@ -873,7 +885,7 @@ export async function exchangeAuthorization(
873885
fetchFn
874886
}: {
875887
metadata?: AuthorizationServerMetadata;
876-
clientInformation: OAuthClientInformation;
888+
clientInformation: OAuthClientInformationFull;
877889
authorizationCode: string;
878890
codeVerifier: string;
879891
redirectUri: string | URL;
@@ -952,7 +964,7 @@ export async function refreshAuthorization(
952964
fetchFn
953965
}: {
954966
metadata?: AuthorizationServerMetadata;
955-
clientInformation: OAuthClientInformation;
967+
clientInformation: OAuthClientInformationFull;
956968
refreshToken: string;
957969
resource?: URL;
958970
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)