Comprehensive tooling for working with OpenAPI definitions
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Security scheme parsing, authentication handling, and user-based auth token extraction for OpenAPI operations.
Retrieve security requirements for an operation with fallback to global API security.
/**
* Get security requirements for this operation
* @returns Array of security requirement objects (OR groups containing AND requirements)
*/
getSecurity(): SecurityRequirementObject[];Usage Examples:
const operation = oas.operation("/users", "post");
const security = operation.getSecurity();
security.forEach((requirement, index) => {
console.log(`Security Option ${index + 1}:`);
Object.entries(requirement).forEach(([schemeName, scopes]) => {
console.log(` ${schemeName}: ${scopes.join(', ') || 'no scopes'}`);
});
});
// Check if operation requires authentication
const requiresAuth = security.length > 0;
console.log(`Authentication required: ${requiresAuth}`);Get security requirements with resolved type information and scheme details.
/**
* Get security requirements with type information
* @param filterInvalid - Filter out invalid/nonexistent security schemes
* @returns Array of OR groups containing AND requirements with type info
*/
getSecurityWithTypes(
filterInvalid?: boolean
): Array<Array<{security: KeyedSecuritySchemeObject, type: SecurityType} | false> | false>;Usage Examples:
const securityWithTypes = operation.getSecurityWithTypes(true); // Filter invalid schemes
securityWithTypes.forEach((orGroup, index) => {
if (!orGroup) return;
console.log(`Security Option ${index + 1}:`);
orGroup.forEach(andRequirement => {
if (!andRequirement) return;
const { security, type } = andRequirement;
console.log(` Type: ${type}`);
console.log(` Scheme: ${security._key}`);
console.log(` Scopes: ${security._requirements?.join(', ') || 'none'}`);
// Type-specific information
if (type === 'Bearer' && security.scheme === 'bearer') {
console.log(` Bearer format: ${security.bearerFormat || 'not specified'}`);
} else if (type === 'Header' && security.in === 'header') {
console.log(` Header name: ${security.name}`);
}
});
});Get security schemes organized by type for easier processing.
/**
* Organize security schemes by type
* @returns Object with security types as keys and arrays of schemes as values
*/
prepareSecurity(): Record<SecurityType, KeyedSecuritySchemeObject[]>;Usage Examples:
const securityByType = operation.prepareSecurity();
// Handle different security types
if (securityByType.Bearer) {
console.log("Bearer tokens supported:");
securityByType.Bearer.forEach(scheme => {
console.log(` ${scheme._key}: ${scheme.bearerFormat || 'JWT'}`);
});
}
if (securityByType.Header) {
console.log("API key headers:");
securityByType.Header.forEach(scheme => {
console.log(` ${scheme.name}: ${scheme._key}`);
});
}
if (securityByType.OAuth2) {
console.log("OAuth2 flows:");
securityByType.OAuth2.forEach(scheme => {
if ('flows' in scheme) {
Object.keys(scheme.flows || {}).forEach(flow => {
console.log(` ${scheme._key}: ${flow} flow`);
});
}
});
}Extract authentication credentials for a specific user from the API definition.
/**
* Get authentication credentials for a user
* @param user - User information with potential auth credentials
* @param selectedApp - Specific app/key to use (optional)
* @returns Authentication data formatted for HAR requests
*/
getAuth(user: User, selectedApp?: number | string): AuthForHAR;Usage Examples:
// User with various auth methods
const user = {
apiKey: "sk-1234567890abcdef",
bearerToken: "eyJhbGciOiJIUzI1NiIs...",
keys: [
{ name: "app1", user: "john", pass: "secret123" },
{ name: "app2", user: "jane", pass: "password456" }
]
};
// Get auth for user
const auth = oas.getAuth(user);
console.log("Authentication data:", auth);
// Get auth for specific app
const appAuth = oas.getAuth(user, "app1");
console.log("App-specific auth:", appAuth);
// Use in HTTP requests
const headers = {};
Object.entries(auth).forEach(([key, value]) => {
if (typeof value === 'string') {
headers[key] = value;
} else if (value && typeof value === 'object' && 'user' in value) {
// Basic auth
const credentials = btoa(`${value.user}:${value.pass}`);
headers['Authorization'] = `Basic ${credentials}`;
}
});/** Security scheme types */
type SecurityType = 'apiKey' | 'Basic' | 'Bearer' | 'Cookie' | 'Header' | 'http' | 'OAuth2' | 'Query';
/** Security scheme with additional metadata */
interface KeyedSecuritySchemeObject extends SecuritySchemeObject {
/** The key for the security scheme */
_key: string;
/** Required scopes for OAuth2 */
_requirements?: string[];
/** Default value for authentication */
'x-default'?: number | string;
}
/** User information for authentication */
interface User {
[key: string]: unknown;
/** Array of app-specific credentials */
keys?: {
[key: string]: unknown;
name: number | string;
pass?: number | string;
user?: number | string;
}[];
}
/** Authentication data for HAR format */
type AuthForHAR = Record<string, number | string | { pass?: string; user?: string }>;
/** Security requirement object */
type SecurityRequirementObject = Record<string, string[]>;const securityByType = operation.prepareSecurity();
if (securityByType.OAuth2) {
securityByType.OAuth2.forEach(scheme => {
if ('flows' in scheme && scheme.flows) {
console.log(`OAuth2 scheme: ${scheme._key}`);
// Authorization Code flow
if (scheme.flows.authorizationCode) {
const flow = scheme.flows.authorizationCode;
console.log(` Auth URL: ${flow.authorizationUrl}`);
console.log(` Token URL: ${flow.tokenUrl}`);
console.log(` Scopes: ${Object.keys(flow.scopes || {}).join(', ')}`);
}
// Client Credentials flow
if (scheme.flows.clientCredentials) {
const flow = scheme.flows.clientCredentials;
console.log(` Token URL: ${flow.tokenUrl}`);
console.log(` Scopes: ${Object.keys(flow.scopes || {}).join(', ')}`);
}
}
});
}// Handle operations requiring multiple auth methods (AND requirements)
const securityWithTypes = operation.getSecurityWithTypes();
securityWithTypes.forEach((orGroup, orIndex) => {
if (!orGroup || orGroup.length <= 1) return;
console.log(`Multi-factor option ${orIndex + 1}:`);
orGroup.forEach(andRequirement => {
if (andRequirement) {
console.log(` Required: ${andRequirement.type} (${andRequirement.security._key})`);
}
});
});// Validate user has required credentials
function validateUserAuth(operation: Operation, user: User): boolean {
const security = operation.getSecurity();
if (security.length === 0) return true; // No auth required
const securityByType = operation.prepareSecurity();
// Check if user satisfies any OR requirement
return Object.entries(securityByType).some(([type, schemes]) => {
return schemes.some(scheme => {
switch (type) {
case 'Bearer':
return 'bearerToken' in user || 'authorization' in user;
case 'Header':
return scheme.name.toLowerCase() in user;
case 'Query':
return scheme.name in user;
case 'Basic':
return 'keys' in user && Array.isArray(user.keys);
default:
return false;
}
});
});
}
const isValid = validateUserAuth(operation, user);
console.log(`User has valid credentials: ${isValid}`);// Handle ReadMe-specific auth defaults
const securityByType = operation.prepareSecurity();
Object.values(securityByType).flat().forEach(scheme => {
if ('x-default' in scheme && scheme['x-default'] !== undefined) {
console.log(`Default value for ${scheme._key}: ${scheme['x-default']}`);
}
});Security handling manages various edge cases:
false in arrays// Safe handling of missing security data
const operation = oas.operation("/public", "get");
const security = operation.getSecurity(); // [] for operations without security
const emptyUser = {};
const auth = oas.getAuth(emptyUser); // {} - empty auth object
// Filter invalid schemes
const validSecurity = operation.getSecurityWithTypes(true);
// Removes false entries for broken security scheme references// Generate headers for HTTP clients
function generateAuthHeaders(operation: Operation, user: User): Record<string, string> {
const auth = oas.getAuth(user);
const headers: Record<string, string> = {};
Object.entries(auth).forEach(([key, value]) => {
if (typeof value === 'string') {
headers[key] = value;
} else if (value && typeof value === 'object') {
// Handle Basic auth
const credentials = btoa(`${value.user}:${value.pass}`);
headers['Authorization'] = `Basic ${credentials}`;
}
});
return headers;
}// Express middleware for API security validation
function securityMiddleware(operation: Operation) {
return (req: Request, res: Response, next: NextFunction) => {
const security = operation.getSecurity();
if (security.length === 0) {
return next(); // No auth required
}
const securityByType = operation.prepareSecurity();
let isAuthenticated = false;
// Check each security type
if (securityByType.Bearer && req.headers.authorization?.startsWith('Bearer ')) {
isAuthenticated = true;
} else if (securityByType.Header) {
isAuthenticated = securityByType.Header.some(scheme =>
req.headers[scheme.name.toLowerCase()]
);
}
if (!isAuthenticated) {
return res.status(401).json({ error: 'Authentication required' });
}
next();
};
}Install with Tessl CLI
npx tessl i tessl/npm-oasdocs