// oauth-validator.ts — OAuth 2.1 Bearer token validation for hosted MCP (SPEC-161).
// Supports two modes:
//   1. API key (SDD_OAUTH_API_KEY) — simplest: token must match env var
//   2. HMAC-signed JWT (SDD_OAUTH_JWT_SECRET) — validates HS256 JWT signature
// Configure via environment variables — no accounts or external services needed.
export function loadOAuthConfig() {
    const apiKey = process.env.SDD_OAUTH_API_KEY;
    const jwtSecret = process.env.SDD_OAUTH_JWT_SECRET;
    if (apiKey) {
        return { enabled: true, mode: 'api-key', apiKey };
    }
    if (jwtSecret) {
        return {
            enabled: true,
            mode: 'jwt-hmac',
            jwtSecret,
            issuer: process.env.SDD_OAUTH_ISSUER,
            audience: process.env.SDD_OAUTH_AUDIENCE,
        };
    }
    return { enabled: false, mode: 'disabled' };
}
export function extractBearerToken(authHeader) {
    if (!authHeader?.startsWith('Bearer ')) {
        return null;
    }
    const token = authHeader.slice(7).trim();
    return token.length > 0 ? token : null;
}
export async function validateToken(token, config) {
    if (!config.enabled) {
        return { valid: true };
    }
    if (config.mode === 'api-key') {
        return token === config.apiKey ? { valid: true } : { valid: false, reason: 'Invalid API key' };
    }
    if (config.mode === 'jwt-hmac') {
        return validateHmacJwt(token, config);
    }
    return { valid: false, reason: 'Unknown auth mode' };
}
// Validate HS256 JWT using Node.js built-in crypto (no external deps).
async function validateHmacJwt(token, config) {
    const parts = token.split('.');
    if (parts.length !== 3) {
        return { valid: false, reason: 'Malformed JWT' };
    }
    const [headerB64, payloadB64, sigB64] = parts;
    const { createHmac } = await import('node:crypto');
    const jwtSecret = config.jwtSecret ?? '';
    const expected = createHmac('sha256', jwtSecret)
        .update(`${headerB64}.${payloadB64}`)
        .digest('base64url');
    if (expected !== sigB64) {
        return { valid: false, reason: 'Invalid JWT signature' };
    }
    let payload;
    try {
        payload = JSON.parse(Buffer.from(payloadB64, 'base64url').toString('utf8'));
    }
    catch {
        return { valid: false, reason: 'Invalid JWT payload' };
    }
    const now = Math.floor(Date.now() / 1000);
    if (typeof payload.exp === 'number' && payload.exp < now) {
        return { valid: false, reason: 'Token expired' };
    }
    if (config.issuer !== undefined && payload.iss !== config.issuer) {
        return { valid: false, reason: 'Invalid issuer' };
    }
    if (config.audience !== undefined && payload.aud !== config.audience) {
        return { valid: false, reason: 'Invalid audience' };
    }
    return { valid: true };
}
//# sourceMappingURL=oauth-validator.js.map