UNPKG

@aashari/mcp-server-aws-sso

Version:

Node.js/TypeScript MCP server for AWS Single Sign-On (SSO). Enables AI systems (LLMs) with tools to initiate SSO login (device auth flow), list accounts/roles, and securely execute AWS CLI commands using temporary credentials. Streamlines AI interaction w

126 lines (125 loc) 5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TokenResponseSchema = exports.DeviceAuthorizationResponseSchema = exports.ClientRegistrationResponseSchema = void 0; exports.post = post; const logger_util_js_1 = require("../utils/logger.util.js"); const retry_util_js_1 = require("../utils/retry.util.js"); const zod_1 = require("zod"); const logger = logger_util_js_1.Logger.forContext('services/vendor.aws.sso.auth.http.ts'); /** * Make a POST request to a URL with JSON body * @param url The URL to post to * @param data The data to send in the request body * @returns The JSON response */ async function post(url, data) { const methodLogger = logger.forMethod('post'); methodLogger.debug(`Making POST request to ${url}`); // Use the retry mechanism for handling potential 429 errors const response = await (0, retry_util_js_1.withRetry)(async () => { const fetchResponse = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data), }); if (!fetchResponse.ok) { let errorBody = await fetchResponse.text(); // Try to parse the error response as JSON try { errorBody = JSON.parse(errorBody); methodLogger.debug('Received error response from API', { status: fetchResponse.status, errorBody, }); } catch { // If parsing fails, keep the text version methodLogger.debug('Received non-JSON error response', { status: fetchResponse.status, errorBody, }); } const error = new Error(typeof errorBody === 'object' && errorBody.error_description ? String(errorBody.error_description) : `Request failed with status ${fetchResponse.status}`); error.$metadata = { httpStatusCode: fetchResponse.status }; // Add OIDC-specific error details if available if (typeof errorBody === 'object') { if (errorBody.error) { error.error = String(errorBody.error); } if (errorBody.error_description) { error.error_description = String(errorBody.error_description); } } // Store the original response for more context error.originalResponse = errorBody; // Special handling for authorization_pending - this is expected during polling // and should not be logged as an error if (typeof errorBody === 'object' && errorBody.error === 'authorization_pending') { methodLogger.debug('Received authorization_pending response'); } else { methodLogger.error(`API request failed: ${error.message}`, error); } throw error; } return fetchResponse; }, { // Define custom retry condition for fetch responses retryCondition: (error) => { // Default retry on 429 responses if (error && typeof error === 'object') { if ('$metadata' in error && typeof error.$metadata === 'object') { const metadata = error.$metadata; return metadata.httpStatusCode === 429; } // Also retry on slow_down OIDC errors if ('error' in error && error.error === 'slow_down') { return true; } } return false; }, // Increase backoff for OIDC slow_down errors initialDelayMs: 2000, maxRetries: 8, }); return (await response.json()); } /** * Zod schema for client registration response */ exports.ClientRegistrationResponseSchema = zod_1.z.object({ clientId: zod_1.z.string(), clientSecret: zod_1.z.string(), expiresAt: zod_1.z.string().optional(), }); /** * Zod schema for device authorization response */ exports.DeviceAuthorizationResponseSchema = zod_1.z.object({ deviceCode: zod_1.z.string(), userCode: zod_1.z.string(), verificationUri: zod_1.z.string(), verificationUriComplete: zod_1.z.string(), expiresIn: zod_1.z.number(), interval: zod_1.z.number(), }); /** * Zod schema for token response */ exports.TokenResponseSchema = zod_1.z.object({ accessToken: zod_1.z.string().optional(), access_token: zod_1.z.string().optional(), refreshToken: zod_1.z.string().optional().nullable(), refresh_token: zod_1.z.string().optional().nullable(), tokenType: zod_1.z.string().optional(), token_type: zod_1.z.string().optional(), expires_in: zod_1.z.number().optional(), expiresIn: zod_1.z.number().optional(), });