diff --git a/src/client/auth.ts b/src/client/auth.ts index 02ace32f..c0bac9e8 100644 --- a/src/client/auth.ts +++ b/src/client/auth.ts @@ -1,7 +1,7 @@ import pkceChallenge from "pkce-challenge"; import { LATEST_PROTOCOL_VERSION } from "../types.js"; -import type { OAuthClientMetadata, OAuthClientInformation, OAuthTokens, OAuthMetadata } from "../shared/auth.js"; -import { OAuthClientInformationSchema, OAuthMetadataSchema, OAuthTokensSchema } from "../shared/auth.js"; +import type { OAuthClientMetadata, OAuthClientInformation, OAuthTokens, OAuthMetadata, OAuthClientInformationFull } from "../shared/auth.js"; +import { OAuthClientInformationFullSchema, OAuthMetadataSchema, OAuthTokensSchema } from "../shared/auth.js"; /** * Implements an end-to-end OAuth client to be used with one MCP server. @@ -36,7 +36,7 @@ export interface OAuthClientProvider { * This method is not required to be implemented if client information is * statically known (e.g., pre-registered). */ - saveClientInformation?(clientInformation: OAuthClientInformation): void | Promise; + saveClientInformation?(clientInformation: OAuthClientInformationFull): void | Promise; /** * Loads any existing OAuth tokens for the current session, or returns @@ -98,12 +98,13 @@ export async function auth( throw new Error("OAuth client information must be saveable for dynamic registration"); } - clientInformation = await registerClient(serverUrl, { + const fullInformation = await registerClient(serverUrl, { metadata, clientMetadata: provider.clientMetadata, }); - await provider.saveClientInformation(clientInformation); + await provider.saveClientInformation(fullInformation); + clientInformation = fullInformation; } // Exchange authorization code for tokens @@ -371,7 +372,7 @@ export async function registerClient( metadata?: OAuthMetadata; clientMetadata: OAuthClientMetadata; }, -): Promise { +): Promise { let registrationUrl: URL; if (metadata) { @@ -396,5 +397,5 @@ export async function registerClient( throw new Error(`Dynamic client registration failed: HTTP ${response.status}`); } - return OAuthClientInformationSchema.parse(await response.json()); + return OAuthClientInformationFullSchema.parse(await response.json()); } \ No newline at end of file diff --git a/src/shared/auth.ts b/src/shared/auth.ts index 1bfd9bd3..d1b0b3fe 100644 --- a/src/shared/auth.ts +++ b/src/shared/auth.ts @@ -79,15 +79,20 @@ export const OAuthClientMetadataSchema = z.object({ }).passthrough(); /** - * RFC 7591 OAuth 2.0 Dynamic Client Registration response + * RFC 7591 OAuth 2.0 Dynamic Client Registration client information */ -export const OAuthClientInformationSchema = OAuthClientMetadataSchema.extend({ +export const OAuthClientInformationSchema = z.object({ client_id: z.string(), client_secret: z.string().optional(), client_id_issued_at: z.number().optional(), client_secret_expires_at: z.number().optional(), }).passthrough(); +/** + * RFC 7591 OAuth 2.0 Dynamic Client Registration full response (client information plus metadata) + */ +export const OAuthClientInformationFullSchema = OAuthClientMetadataSchema.merge(OAuthClientInformationSchema); + /** * RFC 7591 OAuth 2.0 Dynamic Client Registration error response */ @@ -101,4 +106,5 @@ export type OAuthTokens = z.infer; export type OAuthError = z.infer; export type OAuthClientMetadata = z.infer; export type OAuthClientInformation = z.infer; +export type OAuthClientInformationFull = z.infer; export type OAuthClientRegistrationError = z.infer; \ No newline at end of file