microsoft/SimpleRestClients

Token Authentication Question

damianesteban opened this issue · 2 comments

This is a great library, I really like how clean and simple it is. One Question - where would you add a request to fetch / refresh a token? Axios for example has interceptors.

The pattern we've typically followed looks something like the following:

MyCustomAuthHandler will return a promise that blocks until it has a token available (and will have the necessary refresh logic encapsulated within). This allows the REST client to largely ignore the refresh logic, it's only aware that the token may not be available synchronously.

export default class RestClient extends GenericRestClient {
    private _authToken: string | undefined;

    protected _blockRequestUntil(options: ApiCallOptions): SyncTasks.Promise<void> | undefined {
        return MyCustomAuthHandler.getAccessToken().then(token => {
            this._authToken = token;
        });
    }

    protected _getHeaders(options: ApiCallOptions): { [header: string]: string; } {
        return {
            'Authorization': 'Bearer ' + this._authToken,
        };
    }

    getData() {
        return this.performApiGet('myApi');
    }
}

Alternatively, you can do the following, which is similar to the above example but doesn't require a private member variable. _getHeaders will NOT be called until _blockRequestUntil resolves, so if the promise returned there doesn't resolve until you have a valid header, you can be sure inside _getHeaders that you'll have a token available to send.

export default class RestClient extends GenericRestClient {
    private _authToken: string | undefined;

    protected _blockRequestUntil(options: ApiCallOptions): SyncTasks.Promise<void> | undefined {
        return MyCustomAuthHandler.performWhenAccessTokenAvailable();
    }

    protected _getHeaders(options: ApiCallOptions): { [header: string]: string; } {
        return {
            'Authorization': 'Bearer ' + MyCustomAuthHandler.getAccessToken()
        };
    }

    getData() {
        return this.performApiGet('myApi');
    }
}

Awesome, thanks so much! This helps a lot and also gives me some ideas for how I could use the library for more advanced operations.