Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 9 additions & 32 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ import { getConfig } from "./src/config/env.js";
import { TransportError } from "./src/errors/TransportError.js";
import { RateLimitError } from "./src/errors/RateLimitError.js";
import { TimeoutError } from "./src/errors/TimeoutError.js";
import { ioRedisClient } from "./src/queues/OAuth2Token.js";
import "./src/job/oauth2-token-generation-worker.js";
import { scheduleAccessTokenRefresh } from "./src/queues/OAuth2Token.js";
import { OAuth2Handler } from "./src/auth/handlers/OAuth2AuthHandler.js";



Expand All @@ -19,36 +15,17 @@ const { baseURL, authType, credentials, oath2Config, redisConfig, accessTokenURL
// Create an authentication handler
const authHandler = CreateAuthHandler(authType, credentials, oath2Config, accessTokenURL, redisConfig);

if (authType === 'oauth2') {
if (oath2Config && accessTokenURL) {
const oauth2Client = new OAuth2Handler(oath2Config, accessTokenURL, redisConfig);
try {
const data = await oauth2Client.getAccessToken();
if (data?.access_token && data?.expires_in) {
const expirationTime = data.expires_in - 10;
await ioRedisClient.del('next-job-time-for-oauth2-access-token');
await ioRedisClient.set(
'next-job-time-for-oauth2-access-token',
JSON.stringify(expirationTime),
'EX',
expirationTime
);
} else {
console.log("Invalid token");
}
} catch (error) {
console.error(error);
}
}
(async () => {

await scheduleAccessTokenRefresh();
})();
}

// Initialize the transport utility
const transport = new Transport({ baseURL, cacheTTL: 600 }, authHandler);

transport.addMiddleware(async (config) => {
const token = await authHandler.getAccessToken();
if (!token) return config;
if (!config.headers) {
config.headers = {};
}
config.headers['Authorization'] = `Bearer ${token}`;
return config;
});
export {
Transport,
CreateAuthHandler,
Expand Down
22 changes: 6 additions & 16 deletions src/auth/handlers/OAuth2AuthHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,47 +30,37 @@ export interface RedisConfig {

export class OAuth2Handler implements AuthHandler {
private redisConnection: IORedis.Redis;
private accessToken: string | null;
constructor(private config: OAuth2Config, private accessTokenURL: string, redisConfig: RedisConfig | null = null) {
if (redisConfig) {
this.redisConnection = new Redis(redisConfig);
} else {
this.redisConnection = new Redis();
}
this.accessToken = null;
}
async getAccessToken(): Promise<OAuth2Response | null> {
let data = null;
async getAccessToken(): Promise<string> {
let accessToken = null;
const cachedAccessToken = await this.redisConnection.get('microsoft-bc-oauth2-access-token');
data = {
token_type: 'client_credentials',
expires_in: 3599,
ext_expires_in: 3599,
access_token: cachedAccessToken,
} as OAuth2Response;
if (cachedAccessToken) {
this.accessToken = cachedAccessToken;
accessToken = cachedAccessToken;
} else {
const params = new URLSearchParams({
...this.config,
});
const { data: tokenResponse } = await axios.post<OAuth2Response>(this.accessTokenURL, params.toString(), {
const { data } = await axios.post<OAuth2Response>(this.accessTokenURL, params.toString(), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}
});
data = tokenResponse;
await this.redisConnection.del('microsoft-bc-oauth2-access-token');
await this.redisConnection.set('microsoft-bc-oauth2-access-token', data.access_token, "EX", data.expires_in);
this.accessToken = data.access_token;
accessToken = data.access_token;
}
return data
return accessToken
}
authenticate(config: ThirdPartyAxiosRequestConfig): AxiosInstance {
if (!config.headers) {
config.headers = {};
}
config.headers['Authorization'] = `Bearer ${this.accessToken}`;
config.headers['Accept'] = `application/json`;
return axios.create(config as AxiosRequestConfig) as AxiosInstance;
}
Expand Down
47 changes: 0 additions & 47 deletions src/job/oauth2-token-generation-worker.ts

This file was deleted.

39 changes: 0 additions & 39 deletions src/queues/OAuth2Token.ts

This file was deleted.

14 changes: 10 additions & 4 deletions src/transport/Transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class Transport {
private defaultCompany: string;
private cache: NodeCache;
private limiter: Bottleneck;
private middleware: ((config: AxiosRequestConfig) => AxiosRequestConfig)[] = [];
private middleware: ((config: AxiosRequestConfig) => AxiosRequestConfig | Promise<AxiosRequestConfig>)[] = [];
private axiosInstance: AxiosInstance;
private logger: pino.Logger;

Expand All @@ -113,7 +113,6 @@ export class Transport {
httpsAgent: new HttpsAgent({ maxSockets: config.maxSockets || 50, keepAlive: true }),
httpAgent: new Agent({ maxSockets: config.maxSockets || 50, maxFreeSockets: config.maxFreeSockets || 20, keepAlive: true }),
});

this.axiosInstance.interceptors.request.use((config) => {
this.logger.debug({ url: config.url, method: config.method, params: config.params }, 'Outgoing requests');
if (config.params) {
Expand Down Expand Up @@ -371,8 +370,12 @@ export class Transport {
return new TransportError('Error preparing BC 365 filter query', 500, error);
}
}
private addMiddleware(middleware: (config: AxiosRequestConfig) => AxiosRequestConfig): void {
public addMiddleware(middleware: (config: AxiosRequestConfig) => AxiosRequestConfig | Promise<AxiosRequestConfig>): void {
if (typeof middleware !== "function") {
throw new TypeError("Middleware must be a function.");
}
this.middleware.push(middleware);

}
// Clear cache for specific key
clearCache(endpoint: string, options?: RequestOptions): void {
Expand Down Expand Up @@ -423,7 +426,8 @@ export class Transport {
private async request<T>(config: AxiosRequestConfig): Promise<T> {
// Appy middleware
for (const middleware of this.middleware) {
config = middleware(config);
console.log("test function");
config = await middleware(config);
}
try {
const reponse = await this.axiosInstance.request<T>(config);
Expand All @@ -434,4 +438,6 @@ export class Transport {
throw error;
}
}


}