All of the mid-session and step-up auth work
This commit is contained in:
parent
1f31e0f1f8
commit
562bdd00f1
1 changed files with 11437 additions and 1212 deletions
|
|
@ -1,29 +1,48 @@
|
|||
import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
||||
import type {
|
||||
OAuthClientInformation,
|
||||
OAuthClientMetadata,
|
||||
OAuthTokens,
|
||||
} from "@modelcontextprotocol/sdk/shared/auth.js";
|
||||
import type { RemoteConnectRequest } from "../types.js";
|
||||
import type { RemoteAuthState } from "../types.js";
|
||||
|
||||
const REMOTE_OAUTH_STUB_METADATA: OAuthClientMetadata = {
|
||||
redirect_uris: [],
|
||||
scope: "",
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple OAuth client provider that just returns tokens.
|
||||
* Used by the remote server to inject Bearer tokens into transport requests.
|
||||
*
|
||||
* The SDK may invoke {@link auth} on 401; stubs must satisfy the full provider
|
||||
* surface so that path fails with a clear error instead of throwing on
|
||||
* undefined `clientMetadata.scope`.
|
||||
*/
|
||||
export function createTokenAuthProvider(
|
||||
tokens: RemoteConnectRequest["oauthTokens"],
|
||||
): OAuthClientProvider | undefined {
|
||||
if (!tokens) return undefined;
|
||||
export interface RemoteAuthProviderHandle {
|
||||
provider: OAuthClientProvider;
|
||||
setAuthState: (authState: RemoteAuthState) => void;
|
||||
getAuthState: () => RemoteAuthState;
|
||||
}
|
||||
|
||||
function cloneAuthState(state: RemoteAuthState): RemoteAuthState {
|
||||
return {
|
||||
...(state.oauthTokens && {
|
||||
oauthTokens: { ...state.oauthTokens },
|
||||
}),
|
||||
...(state.oauthClient && {
|
||||
oauthClient: { ...state.oauthClient },
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutable OAuth provider for the remote backend MCP transport.
|
||||
* Browser (or CLI) owns interactive OAuth; this injects Bearer tokens and can
|
||||
* be hot-updated via {@link RemoteAuthProviderHandle.setAuthState}.
|
||||
*/
|
||||
export function createRemoteAuthProvider(
|
||||
initialAuthState?: RemoteAuthState,
|
||||
): RemoteAuthProviderHandle | undefined {
|
||||
if (!initialAuthState?.oauthTokens && !initialAuthState?.oauthClient) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let authState = cloneAuthState(initialAuthState);
|
||||
|
||||
const provider = {
|
||||
get clientMetadata(): OAuthClientMetadata {
|
||||
return REMOTE_OAUTH_STUB_METADATA;
|
||||
},
|
||||
|
|
@ -31,13 +50,31 @@ export function createTokenAuthProvider(
|
|||
return "";
|
||||
},
|
||||
async tokens(): Promise<OAuthTokens | undefined> {
|
||||
return tokens as OAuthTokens;
|
||||
return authState.oauthTokens as OAuthTokens | undefined;
|
||||
},
|
||||
async clientInformation() {
|
||||
return undefined;
|
||||
async clientInformation(): Promise<OAuthClientInformation | undefined> {
|
||||
if (!authState.oauthClient?.client_id) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
client_id: authState.oauthClient.client_id,
|
||||
...(authState.oauthClient.client_secret && {
|
||||
client_secret: authState.oauthClient.client_secret,
|
||||
}),
|
||||
};
|
||||
},
|
||||
async saveTokens() {
|
||||
// No-op
|
||||
async saveTokens(tokens: OAuthTokens) {
|
||||
authState = {
|
||||
...authState,
|
||||
oauthTokens: {
|
||||
access_token: tokens.access_token,
|
||||
token_type: tokens.token_type,
|
||||
expires_in: tokens.expires_in,
|
||||
refresh_token: tokens.refresh_token,
|
||||
scope: tokens.scope,
|
||||
id_token: tokens.id_token,
|
||||
},
|
||||
};
|
||||
},
|
||||
codeVerifier() {
|
||||
return undefined;
|
||||
|
|
@ -46,7 +83,7 @@ export function createTokenAuthProvider(
|
|||
// No-op
|
||||
},
|
||||
clear() {
|
||||
// No-op
|
||||
authState = {};
|
||||
},
|
||||
async redirectToAuthorization() {
|
||||
throw new Error(
|
||||
|
|
@ -57,4 +94,14 @@ export function createTokenAuthProvider(
|
|||
return "";
|
||||
},
|
||||
} as unknown as OAuthClientProvider;
|
||||
|
||||
return {
|
||||
provider,
|
||||
setAuthState(next: RemoteAuthState) {
|
||||
authState = cloneAuthState(next);
|
||||
},
|
||||
getAuthState() {
|
||||
return cloneAuthState(authState);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue