* wip auth debugger * cleanup types and validation * more cleanup * draft test * wip clean up some * rm toasts * consolidate state management * prettier * hoist state up to App * working with quick and guided * sort out displaying debugger * prettier * cleanup types * fix tests * cleanup comment * prettier * fixup types in tests * prettier * refactor debug to avoid toasting * callback shuffling * linting * types * rm toast in test * bump typescript sdk version to 0.11.2 for scope parameter passing * use proper scope handling * test scope parameter passing * move functions and s/sseUrl/serverUrl/ * extract status message into component * refactor progress and steps into components * fix test * rename quick handler * one less click * last step complete * add state machine * test and types
141 lines
3.8 KiB
TypeScript
141 lines
3.8 KiB
TypeScript
import { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
import {
|
|
OAuthClientInformationSchema,
|
|
OAuthClientInformation,
|
|
OAuthTokens,
|
|
OAuthTokensSchema,
|
|
OAuthClientMetadata,
|
|
OAuthMetadata,
|
|
} from "@modelcontextprotocol/sdk/shared/auth.js";
|
|
import { SESSION_KEYS, getServerSpecificKey } from "./constants";
|
|
|
|
export class InspectorOAuthClientProvider implements OAuthClientProvider {
|
|
constructor(public serverUrl: string) {
|
|
// Save the server URL to session storage
|
|
sessionStorage.setItem(SESSION_KEYS.SERVER_URL, serverUrl);
|
|
}
|
|
|
|
get redirectUrl() {
|
|
return window.location.origin + "/oauth/callback";
|
|
}
|
|
|
|
get clientMetadata(): OAuthClientMetadata {
|
|
return {
|
|
redirect_uris: [this.redirectUrl],
|
|
token_endpoint_auth_method: "none",
|
|
grant_types: ["authorization_code", "refresh_token"],
|
|
response_types: ["code"],
|
|
client_name: "MCP Inspector",
|
|
client_uri: "https://github.com/modelcontextprotocol/inspector",
|
|
};
|
|
}
|
|
|
|
async clientInformation() {
|
|
const key = getServerSpecificKey(
|
|
SESSION_KEYS.CLIENT_INFORMATION,
|
|
this.serverUrl,
|
|
);
|
|
const value = sessionStorage.getItem(key);
|
|
if (!value) {
|
|
return undefined;
|
|
}
|
|
|
|
return await OAuthClientInformationSchema.parseAsync(JSON.parse(value));
|
|
}
|
|
|
|
saveClientInformation(clientInformation: OAuthClientInformation) {
|
|
const key = getServerSpecificKey(
|
|
SESSION_KEYS.CLIENT_INFORMATION,
|
|
this.serverUrl,
|
|
);
|
|
sessionStorage.setItem(key, JSON.stringify(clientInformation));
|
|
}
|
|
|
|
async tokens() {
|
|
const key = getServerSpecificKey(SESSION_KEYS.TOKENS, this.serverUrl);
|
|
const tokens = sessionStorage.getItem(key);
|
|
if (!tokens) {
|
|
return undefined;
|
|
}
|
|
|
|
return await OAuthTokensSchema.parseAsync(JSON.parse(tokens));
|
|
}
|
|
|
|
saveTokens(tokens: OAuthTokens) {
|
|
const key = getServerSpecificKey(SESSION_KEYS.TOKENS, this.serverUrl);
|
|
sessionStorage.setItem(key, JSON.stringify(tokens));
|
|
}
|
|
|
|
redirectToAuthorization(authorizationUrl: URL) {
|
|
window.location.href = authorizationUrl.href;
|
|
}
|
|
|
|
saveCodeVerifier(codeVerifier: string) {
|
|
const key = getServerSpecificKey(
|
|
SESSION_KEYS.CODE_VERIFIER,
|
|
this.serverUrl,
|
|
);
|
|
sessionStorage.setItem(key, codeVerifier);
|
|
}
|
|
|
|
codeVerifier() {
|
|
const key = getServerSpecificKey(
|
|
SESSION_KEYS.CODE_VERIFIER,
|
|
this.serverUrl,
|
|
);
|
|
const verifier = sessionStorage.getItem(key);
|
|
if (!verifier) {
|
|
throw new Error("No code verifier saved for session");
|
|
}
|
|
|
|
return verifier;
|
|
}
|
|
|
|
clear() {
|
|
sessionStorage.removeItem(
|
|
getServerSpecificKey(SESSION_KEYS.CLIENT_INFORMATION, this.serverUrl),
|
|
);
|
|
sessionStorage.removeItem(
|
|
getServerSpecificKey(SESSION_KEYS.TOKENS, this.serverUrl),
|
|
);
|
|
sessionStorage.removeItem(
|
|
getServerSpecificKey(SESSION_KEYS.CODE_VERIFIER, this.serverUrl),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Overrides debug URL and allows saving server OAuth metadata to
|
|
// display in debug UI.
|
|
export class DebugInspectorOAuthClientProvider extends InspectorOAuthClientProvider {
|
|
get redirectUrl(): string {
|
|
return `${window.location.origin}/oauth/callback/debug`;
|
|
}
|
|
|
|
saveServerMetadata(metadata: OAuthMetadata) {
|
|
const key = getServerSpecificKey(
|
|
SESSION_KEYS.SERVER_METADATA,
|
|
this.serverUrl,
|
|
);
|
|
sessionStorage.setItem(key, JSON.stringify(metadata));
|
|
}
|
|
|
|
getServerMetadata(): OAuthMetadata | null {
|
|
const key = getServerSpecificKey(
|
|
SESSION_KEYS.SERVER_METADATA,
|
|
this.serverUrl,
|
|
);
|
|
const metadata = sessionStorage.getItem(key);
|
|
if (!metadata) {
|
|
return null;
|
|
}
|
|
return JSON.parse(metadata);
|
|
}
|
|
|
|
clear() {
|
|
super.clear();
|
|
sessionStorage.removeItem(
|
|
getServerSpecificKey(SESSION_KEYS.SERVER_METADATA, this.serverUrl),
|
|
);
|
|
}
|
|
}
|