UNPKG

@fairmint/canton-node-sdk

Version:
133 lines 5.85 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AuthenticationManager = void 0; const axios_1 = __importDefault(require("axios")); const url_1 = require("url"); const errors_1 = require("../errors"); /** Manages OAuth2 authentication and token lifecycle */ class AuthenticationManager { constructor(authUrl, authConfig, logger) { this.authUrl = authUrl; this.authConfig = authConfig; this.logger = logger; this.bearerToken = null; this.tokenExpiry = null; } async authenticate() { // Check if we have a valid token if (this.isTokenValid()) { return this.bearerToken; } // Check if authentication credentials are provided if (!this.authConfig.clientId || this.authConfig.clientId.trim() === '') { // No authentication credentials provided, skip authentication this.bearerToken = null; return ''; } // Validate required auth configuration this.validateAuthConfig(); const formData = new url_1.URLSearchParams(); formData.append('grant_type', this.authConfig.grantType); formData.append('client_id', this.authConfig.clientId); if (this.authConfig.clientSecret) { formData.append('client_secret', this.authConfig.clientSecret); } if (this.authConfig.audience) { formData.append('audience', this.authConfig.audience); } if (this.authConfig.scope) { formData.append('scope', this.authConfig.scope); } if (this.authConfig.username) { formData.append('username', this.authConfig.username); } if (this.authConfig.password) { formData.append('password', this.authConfig.password); } const url = this.authUrl + '/'; const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; // Build a log-friendly representation of the request body const requestBody = {}; for (const [key, value] of formData.entries()) { requestBody[key] = value; } try { const response = await axios_1.default.post(url, formData.toString(), { headers, }); if (!response.data.access_token) { throw new errors_1.AuthenticationError(`Authentication response missing access_token. Response: ${JSON.stringify(response.data, null, 2)}`); } this.bearerToken = response.data.access_token; // Set token expiry if provided if (response.data.expires_in) { this.tokenExpiry = Date.now() + (response.data.expires_in * 1000); } // Log success if (this.logger) { await this.logger.logRequestResponse(url, { method: 'POST', headers, data: requestBody }, response.data); } return this.bearerToken; } catch (error) { // Log failure with context if (this.logger) { const errorPayload = axios_1.default.isAxiosError(error) ? (error.response?.data || error.message) : (error instanceof Error ? error.message : String(error)); await this.logger.logRequestResponse(url, { method: 'POST', headers, data: requestBody }, errorPayload); } if (axios_1.default.isAxiosError(error)) { const status = error.response?.status; const statusText = error.response?.statusText; const errorData = error.response?.data ? JSON.stringify(error.response.data, null, 2) : error.message; throw new errors_1.ApiError(`Authentication failed for URL ${url} with status ${status} ${statusText}: ${errorData}`, status, statusText); } throw new errors_1.AuthenticationError(`Authentication failed for URL ${url}: ${error instanceof Error ? error.message : String(error)}`); } } async getBearerToken() { return this.authenticate(); } clearToken() { this.bearerToken = null; this.tokenExpiry = null; } validateAuthConfig() { const missingConfig = []; if (!this.authConfig.clientId) missingConfig.push('clientId'); if (!this.authConfig.grantType) missingConfig.push('grantType'); // Check for grant type specific requirements if (this.authConfig.grantType === 'password') { if (!this.authConfig.username) missingConfig.push('username'); if (!this.authConfig.password) missingConfig.push('password'); } // Note: client_credentials grant type may not always require client_secret // Some providers allow client_credentials without secret for public clients if (missingConfig.length > 0) { throw new errors_1.AuthenticationError(`Authentication configuration incomplete. Missing required fields: ${missingConfig.join(', ')}. ` + `Grant Type: ${this.authConfig.grantType}`); } } isTokenValid() { if (!this.bearerToken) { return false; } // If no expiry is set, assume token is valid if (!this.tokenExpiry) { return true; } // Check if token has expired (with 5 minute buffer) const bufferTime = 5 * 60 * 1000; // 5 minutes return Date.now() < (this.tokenExpiry - bufferTime); } } exports.AuthenticationManager = AuthenticationManager; //# sourceMappingURL=AuthenticationManager.js.map