UNPKG

service-titan-api

Version:

A module for authenticating and accessing the ServiceTitan API.

71 lines (66 loc) 2.48 kB
// src/auth/serviceTitanAuth.mjs import axios from "axios"; export default class ServiceTitanAuth { /** * @param {Object} options * @param {string} options.clientId - Your ServiceTitan Client ID * @param {string} options.clientSecret - Your ServiceTitan Client Secret * @param {string} [options.environment='integration'] - Environment ('integration' or 'production') */ constructor({ clientId, clientSecret, environment = "integration" }) { if (!clientId || !clientSecret) { throw new Error("clientId and clientSecret are required"); } this.clientId = clientId; this.clientSecret = clientSecret; this.environment = environment; this.authUrl = environment === "integration" ? "https://auth-integration.servicetitan.io/connect/token" : "https://auth.servicetitan.io/connect/token"; this.accessToken = null; this.expiresAt = 0; } /** * Returns a valid access token. If the current token is expired or about to expire, * it will automatically fetch a new one. * @returns {Promise<string>} The ServiceTitan access token. */ async getAccessToken() { if (this.accessToken && Date.now() < this.expiresAt) { return this.accessToken; } return this.fetchNewToken(); } /** * Fetches a new access token from the ServiceTitan OAuth API using axios. * @returns {Promise<string>} The new access token. */ async fetchNewToken() { const body = new URLSearchParams(); body.append("grant_type", "client_credentials"); body.append("client_id", this.clientId); body.append("client_secret", this.clientSecret); try { const response = await axios.post(this.authUrl, body.toString(), { headers: { "Content-Type": "application/x-www-form-urlencoded" }, }); const data = response.data; this.accessToken = data.access_token; // Subtract a safety margin (30 seconds) from expires_in. this.expiresAt = Date.now() + (data.expires_in - 30) * 1000; return this.accessToken; } catch (error) { const status = error.response ? error.response.status : "Unknown status"; const statusText = error.response ? error.response.statusText : "Unknown error"; const errorData = error.response ? JSON.stringify(error.response.data) : error.message; throw new Error( `Error fetching token: ${status} ${statusText}: ${errorData}` ); } } }