Home | Getting Started | SSRF Prevention
The SecurityResolver class handles OpenAPI security schemes and converts them to actual HTTP auth values. It works with any OpenAPI security scheme name -- your spec can call it BearerAuth, JWT, MyCustomAuth, etc. The resolver uses the scheme's type and metadata, not its name.
- Generation: OpenAPI security schemes become
SecurityParameterInfoentries on mapper items - Resolution:
SecurityResolver.resolve()maps aSecurityContextto actual headers/query/cookies - Execution: Your framework applies the resolved values to HTTP requests
import { OpenAPIToolGenerator, SecurityResolver, createSecurityContext } from 'mcp-from-openapi';
// 1. Generate tools
const generator = await OpenAPIToolGenerator.fromJSON(spec);
const tools = await generator.generateTools();
// 2. Resolve security for a tool
const resolver = new SecurityResolver();
const context = createSecurityContext({
jwt: 'eyJhbGciOiJIUzI1NiIs...',
apiKey: 'sk-abc123',
});
const resolved = await resolver.resolve(tools[0].mapper, context);
// 3. Apply to HTTP request
const response = await fetch(url, {
headers: { ...resolved.headers },
// resolved.query, resolved.cookies also available
});const context = createSecurityContext({
jwt: 'eyJhbGciOiJIUzI1NiIs...',
});
// Produces: { headers: { Authorization: "Bearer eyJhbGci..." } }Works with any HTTP bearer scheme, regardless of the OpenAPI scheme name.
const context = createSecurityContext({
basic: btoa('username:password'), // Base64 encoded
});
// Produces: { headers: { Authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" } }const context = createSecurityContext({
digest: {
username: 'user',
password: 'pass',
realm: 'example.com',
nonce: 'abc123',
uri: '/api/data',
qop: 'auth',
nc: '00000001',
cnonce: 'xyz789',
response: 'computed-hash',
opaque: 'opaque-value',
},
});
// Produces: { headers: { Authorization: "Digest username=\"user\", realm=\"example.com\", ..." } }const context = createSecurityContext({
apiKey: 'sk-abc123',
});
// Depending on the scheme's "in" field:
// header: { headers: { "X-API-Key": "sk-abc123" } }
// query: { query: { "api_key": "sk-abc123" } }
// cookie: { cookies: { "api_key": "sk-abc123" } }When your API requires different keys for different purposes:
const context = createSecurityContext({
apiKeys: {
'X-API-Key': 'key-for-auth',
'X-Client-Id': 'client-123',
},
});Named API keys are matched by the scheme's apiKeyName from the OpenAPI spec.
const context = createSecurityContext({
oauth2Token: 'access-token-here',
});
// Produces: { headers: { Authorization: "Bearer access-token-here" } }const context = createSecurityContext({
clientCertificate: {
cert: '-----BEGIN CERTIFICATE-----\n...',
key: '-----BEGIN PRIVATE KEY-----\n...',
passphrase: 'optional-passphrase',
ca: '-----BEGIN CERTIFICATE-----\n...',
},
});
// resolved.clientCertificate is set for your HTTP client to useFor proprietary auth schemes:
const context = createSecurityContext({
customHeaders: {
'X-Custom-Auth': 'custom-value',
'X-Tenant-Id': 'tenant-123',
},
});For framework-specific auth (e.g., pulling tokens from a session store):
const context = createSecurityContext({
customResolver: async (security) => {
if (security.type === 'http' && security.httpScheme === 'bearer') {
return await mySessionStore.getToken();
}
if (security.type === 'apiKey') {
return await myVault.getSecret(security.apiKeyName);
}
return undefined; // Fall through to default resolution
},
});The custom resolver is tried first for every security parameter. Return undefined to fall through to built-in resolution.
For HMAC, AWS Signature V4, and other signature-based schemes:
const context = createSecurityContext({
signatureGenerator: async (data, security) => {
// data: { method, url, headers, body, timestamp }
// security: SecurityParameterInfo
const signature = await computeHMAC(data, mySecret);
return signature;
},
});
const resolved = await resolver.resolve(tool.mapper, context);
if (resolved.requiresSignature) {
const signedHeaders = await resolver.signRequest(
tool.mapper,
{
method: 'GET',
url: 'https://api.example.com/data',
headers: resolved.headers,
},
context,
);
// Use signedHeaders in your request
}Schemes with names containing aws4, hmac, signature, hawk, or custom-signature are automatically detected as signature-based.
Validate that all required security is available before making requests:
const missing = await resolver.checkMissingSecurity(tool.mapper, context);
if (missing.length > 0) {
console.error('Missing security schemes:', missing);
// e.g., ["BearerAuth", "ApiKeyAuth"]
}By default, security parameters only appear in the mapper (with a security field). Set includeSecurityInInput: true to also add them to the inputSchema:
const tools = await generator.generateTools({
includeSecurityInInput: true,
});
// Now inputSchema includes security params:
// { properties: { BearerAuth: { type: "string", description: "Bearer authentication token" } } }This is useful when callers provide auth values directly (e.g., in testing or when the framework doesn't manage auth).
Security mapper entries have a security field:
for (const m of tool.mapper) {
if (m.security) {
console.log(`Auth: ${m.security.scheme} (${m.security.type})`);
console.log(` Header: ${m.key}`);
console.log(` HTTP scheme: ${m.security.httpScheme}`);
}
}Related: SSRF Prevention | Configuration | API Reference