Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for async auth provider #147

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ You can get more data on the Fireblocks error using the following fields:
- `error.response.data.message`: Explanation of the Fireblocks error
- `error.response.headers['x-request-id']`: The request ID correlated to the API request, should be provided on support tickets / Github issues

#### Auth Provider
You can supply an async auth provider instance that implements the following interface:
```ts
export interface IAuthProvider {
signJwt(path: string, bodyJson?: any): string | Promise<string>;

getApiKey(): string | Promise<string>;
}
```


Methods can be async.
22 changes: 12 additions & 10 deletions src/api-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ export class ApiClient {
baseURL: this.apiBaseUrl,
proxy: this.options?.proxy,
timeout: this.options?.timeoutInMs,
headers: {
"X-API-Key": this.authProvider.getApiKey(),
"User-Agent": this.getUserAgent()
}
});

this.axiosInstance.interceptors.request.use(async (config: any) => {
config.headers.common["X-API-Key"] = await this.authProvider.getApiKey();
config.headers.common["User-Agent"] = this.getUserAgent();
return config;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we run this on every request? These header don't change. But if we already have an interceptor, let's move signJwt() into it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do you suggest calculating it if not here? It's an async function, can't execute it in the constructor

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree.
We should move sign_jwt() in here as well.
This way the consumer can use the same SDK instance to run commands on multiple accounts. Because the API Key and the JWT are coupled it makes little sense to allow changing only one.

});

if (options.customAxiosOptions?.interceptors?.response) {
Expand All @@ -37,7 +39,7 @@ export class ApiClient {
}

public async issueGetRequestForTransactionPages(path: string): Promise<TransactionPageResponse> {
const token = this.authProvider.signJwt(path);
const token = await this.authProvider.signJwt(path);
const res = await this.axiosInstance.get(path, {
headers: {"Authorization": `Bearer ${token}`}
});
Expand All @@ -51,15 +53,15 @@ export class ApiClient {
}

public async issueGetRequest<T>(path: string): Promise<T> {
const token = this.authProvider.signJwt(path);
const token = await this.authProvider.signJwt(path);
const res = await this.axiosInstance.get(path, {
headers: {"Authorization": `Bearer ${token}`}
});
return res.data;
}

public async issuePostRequest<T>(path: string, body: any, requestOptions?: RequestOptions): Promise<T> {
const token = this.authProvider.signJwt(path, body);
const token = await this.authProvider.signJwt(path, body);
const headers: any = {"Authorization": `Bearer ${token}`};
const idempotencyKey = requestOptions?.idempotencyKey;
if (idempotencyKey) {
Expand All @@ -70,23 +72,23 @@ export class ApiClient {
}

public async issuePutRequest<T>(path: string, body: any): Promise<T> {
const token = this.authProvider.signJwt(path, body);
const token = await this.authProvider.signJwt(path, body);
const res = (await this.axiosInstance.put<T>(path, body, {
headers: {"Authorization": `Bearer ${token}`}
}));
return res.data;
}

public async issuePatchRequest<T>(path: string, body: any): Promise<T> {
const token = this.authProvider.signJwt(path, body);
const token = await this.authProvider.signJwt(path, body);
const res = (await this.axiosInstance.patch<T>(path, body, {
headers: {"Authorization": `Bearer ${token}`}
}));
return res.data;
}

public async issueDeleteRequest<T>(path: string): Promise<T> {
const token = this.authProvider.signJwt(path);
const token = await this.authProvider.signJwt(path);
const res = (await this.axiosInstance.delete<T>(path, {
headers: {"Authorization": `Bearer ${token}`}
}));
Expand Down
2 changes: 2 additions & 0 deletions src/fireblocks-sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ import { AxiosInterceptorOptions, AxiosProxyConfig, AxiosResponse } from "axios"

export * from "./types";

export * from "./iauth-provider";

export interface SDKOptions {
/** HTTP request timeout */
timeoutInMs?: number;
Expand Down
4 changes: 2 additions & 2 deletions src/iauth-provider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export interface IAuthProvider {
signJwt(path: string, bodyJson?: any): string;
signJwt(path: string, bodyJson?: any): string | Promise<string>;

getApiKey(): string;
getApiKey(): string | Promise<string>;
}