@dvsa/appdev-api-common
Version:
Utils library for common API functionality
93 lines (92 loc) • 3.48 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientCredentials = void 0;
const node_querystring_1 = require("node:querystring");
const jose_1 = require("jose");
class ClientCredentials {
tokenUrl;
clientId;
clientSecret;
scope;
resource;
debugMode;
static accessToken;
static grantType = "client_credentials";
/**
* Create a new instance of the ClientCredentials class
* @param tokenUrl - The URL to fetch the access token from
* @param clientId - The client id
* @param clientSecret - The client secret
* @param scope - The scope of the access token
* @param debugMode - Whether to log debug messages
*/
constructor(tokenUrl, clientId, clientSecret, scope, resource, debugMode = false) {
this.tokenUrl = tokenUrl;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.scope = scope;
this.resource = resource;
this.debugMode = debugMode;
}
/**
* Helper method to perform the client credentials flow and return the access token
* This method will check for the existence of the token and if it is expired, it will fetch a new one
* @returns {Promise<string>} - The access token
*/
async getAccessToken() {
if (!ClientCredentials.accessToken || this.isAccessTokenExpired()) {
const { access_token } = await this.fetchClientCredentials();
if (this.debugMode)
console.log("[DEBUG] New access token fetched:", access_token);
ClientCredentials.accessToken = access_token;
}
else if (this.debugMode) {
console.log("[DEBUG] Using existing access token:", ClientCredentials.accessToken);
}
return ClientCredentials.accessToken;
}
/**
* Fetch the client credentials from the token URL
* @returns {Promise<ClientCredentialsResponse>} - The response from the token URL
* @private
*/
async fetchClientCredentials() {
const response = await fetch(this.tokenUrl, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: (0, node_querystring_1.stringify)({
grant_type: ClientCredentials.grantType,
client_id: this.clientId,
client_secret: this.clientSecret,
scope: this.scope,
resource: this.resource,
}),
});
if (!response.ok) {
console.error("Error fetching client credentials", response);
throw new Error("Failed to fetch client credentials");
}
return (await response.json());
}
/**
* Check if the access token is expired
* @returns {boolean} - Whether the access token is expired
* @private
*/
isAccessTokenExpired() {
try {
const decodedAccessToken = (0, jose_1.decodeJwt)(ClientCredentials.accessToken);
const currentTime = new Date().getTime() / 1000;
// Check if exp exists before comparing as it can be undefined
if (!decodedAccessToken?.exp) {
return true;
}
return currentTime > decodedAccessToken.exp;
}
catch (err) {
console.error("Error decoding access token:", err);
return true;
}
}
}
exports.ClientCredentials = ClientCredentials;