// tools/configure-auth-handler.ts — Handler for configure_auth tool (SPEC-161)
// Persists OAuth 2.1 provider config. Never persists tokens.
import { saveAuthConfig, loadAuthConfig, resetAuthConfigCache, generatePkceChallenge, } from '../engine/auth/index.js';
/**
 * Handle the configure_auth tool call.
 * Validates input, saves configuration, and returns a PKCE challenge
 * so the caller can initiate the authorization code flow immediately.
 */
export async function handleConfigureAuth(args) {
    if (!args.introspectionUrl && !args.jwksUrl) {
        return errorResult('Either introspectionUrl or jwksUrl must be provided for token validation. ' +
            'Use introspectionUrl for opaque tokens or jwksUrl for JWT tokens.');
    }
    const config = {
        clientId: args.clientId,
        authorizationUrl: args.authorizationUrl,
        tokenUrl: args.tokenUrl,
        introspectionUrl: args.introspectionUrl,
        jwksUrl: args.jwksUrl,
        scopes: args.scopes,
        scopeMappings: args.scopeMappings ?? {},
        updatedAt: new Date().toISOString(),
    };
    try {
        await saveAuthConfig(config);
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        return errorResult(`Failed to save auth config: ${message}`);
    }
    const pkce = generatePkceChallenge();
    const lines = buildSuccessOutput(config, pkce.codeChallenge, pkce.codeVerifier);
    return { content: [{ type: 'text', text: lines.join('\n') }] };
}
/**
 * Build human-readable output for a successful configure_auth call.
 * Includes the PKCE challenge and next-step authorization URL.
 */
function buildSuccessOutput(config, codeChallenge, codeVerifier) {
    const authUrl = buildAuthorizationUrl(config, codeChallenge);
    return [
        '# OAuth 2.1 Authentication Configured',
        '',
        `Client ID     : ${config.clientId}`,
        `Authorization : ${config.authorizationUrl}`,
        `Token URL     : ${config.tokenUrl}`,
        config.introspectionUrl ? `Introspection : ${config.introspectionUrl}` : '',
        config.jwksUrl ? `JWKS URI      : ${config.jwksUrl}` : '',
        `Scopes        : ${config.scopes.join(', ')}`,
        '',
        '## PKCE Authorization Flow',
        '',
        'Store the code verifier securely — you will need it at the token exchange step.',
        '(Retrieve the full verifier programmatically; it is masked here for security.)',
        '',
        // Security: never expose the full verifier in tool output — an LLM conversation
        // may be logged or shared. The caller should store it via a secure channel, not
        // by copy-pasting from this text output.
        `Code Verifier  : ${maskSecret(codeVerifier)}`,
        `Code Challenge : ${codeChallenge}`,
        `Method         : S256`,
        '',
        '## Next Step — Open this URL to authorize:',
        '',
        authUrl,
        '',
        'After authorization, exchange the code with:',
        `POST ${config.tokenUrl}`,
        `  grant_type=authorization_code`,
        `  code=<received_code>`,
        `  code_verifier=<stored_verifier>`,
        `  client_id=${config.clientId}`,
        '',
        'The MCP server will now validate Bearer tokens on each request (hosted mode).',
        'Local stdio connections remain unaffected.',
    ].filter((line) => line !== '');
}
/** Build the authorization URL with PKCE and scope parameters. */
function buildAuthorizationUrl(config, codeChallenge) {
    const params = new URLSearchParams({
        response_type: 'code',
        client_id: config.clientId,
        scope: config.scopes.join(' '),
        code_challenge: codeChallenge,
        code_challenge_method: 'S256',
    });
    return `${config.authorizationUrl}?${params.toString()}`;
}
/**
 * Mask a secret value for display: show first 4 + last 4 chars only.
 * The full value should be retrieved programmatically, never from tool output.
 */
function maskSecret(value) {
    if (value.length <= 8) {
        return '****';
    }
    return `${value.slice(0, 4)}...${value.slice(-4)}`;
}
function errorResult(message) {
    return {
        content: [{ type: 'text', text: `Error configuring auth: ${message}` }],
        isError: true,
    };
}
/**
 * Reset auth config state — for testing only.
 */
export function resetAuthConfig() {
    resetAuthConfigCache();
}
/** Re-export for external callers that need the current config. */
export { loadAuthConfig };
//# sourceMappingURL=configure-auth-handler.js.map