Skip to content

Commit

Permalink
fix(requestbuilder): regenerate access token if refresh fails
Browse files Browse the repository at this point in the history
  • Loading branch information
meriamBenSassi committed May 30, 2021
1 parent 7ee3d2b commit 5b9df4d
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 35 deletions.
73 changes: 39 additions & 34 deletions src/RequestBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,46 +93,19 @@ export class RequestBuilder {
}

if (this.accessTokenInstance !== undefined && isAccessTokenExpired && !isRefreshTokenExpired) {
const token: AxiosResponse<OAuthResponse> = await Axios.post<OAuthResponse>(
`${this.baseUrl}/v${this.apiVersion}/oauth/token`,
stringify({
refresh_token: this.accessTokenInstance.refresh_token,
grant_type: 'refresh_token',
client_id: this.credentials.clientId,
client_secret: this.credentials.clientSecret,
}),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
},
);
let token: AxiosResponse<OAuthResponse>;
try {
token = await this.generateToken(true);
} catch (err) {
token = await this.generateToken();
}

this.accessTokenInstance = this.getAccessTokenInstance(token.data);

return `Bearer ${this.accessTokenInstance.access_token}`;
}

const grantType: string =
this.credentials.username !== undefined && this.credentials.password !== undefined
? 'password'
: 'client_credentials';

const request: AxiosResponse<OAuthResponse> = await Axios.post<OAuthResponse>(
`${this.baseUrl}/v${this.apiVersion}/oauth/token`,
stringify({
client_id: this.credentials.clientId,
client_secret: this.credentials.clientSecret,
username: this.credentials.username,
password: this.credentials.password,
grant_type: grantType,
}),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
},
);
const request: AxiosResponse<OAuthResponse> = await this.generateToken();

this.accessTokenInstance = this.getAccessTokenInstance(request.data);

Expand Down Expand Up @@ -195,6 +168,38 @@ export class RequestBuilder {
// eslint-disable-next-line no-underscore-dangle
return this._authorizationHeader;
}

/**
* Call the auth route to generate a token
* @param fromRefreshToken if set to true, use the grant type refresh_token
* @returns
*/
private generateToken(fromRefreshToken: boolean = false): Promise<AxiosResponse<OAuthResponse>> {
const grantType: string =
this.credentials.username !== undefined && this.credentials.password !== undefined
? 'password'
: 'client_credentials';

const body = fromRefreshToken
? {
refresh_token: (this.accessTokenInstance as AccessToken).refresh_token,
grant_type: 'refresh_token',
client_id: this.credentials.clientId,
client_secret: this.credentials.clientSecret,
}
: {
client_id: this.credentials.clientId,
client_secret: this.credentials.clientSecret,
username: this.credentials.username,
password: this.credentials.password,
grant_type: grantType,
};
return Axios.post<OAuthResponse>(`${this.baseUrl}/v${this.apiVersion}/oauth/token`, stringify(body), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
}
}

/**
Expand Down
49 changes: 49 additions & 0 deletions test/request-builder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,4 +473,53 @@ describe('Tests related to the RequestBuilder class', () => {
expect((requestBuilder as any).accessTokenInstance).toBeUndefined();
expect((requestBuilder as any)._authorizationHeader).toBeDefined();
});

it('RB012 - should call the token API twice - error on refresh', async () => {
const requestBuilder: RequestBuilder = new RequestBuilder(baseUrl, {
clientId: 'clientId',
clientSecret: 'clientSecret',
});
const oAuthServer: nock.Scope = getOAuthServer({
baseUrl,
isRefreshToken: false,
isUserPassword: false,
nbOfCalls: 2,
expiresIn: 0.05,
refreshExpiresIn: 1000,
});
const refreshTokenServer: nock.Scope = getOAuthServer({
baseUrl,
isRefreshToken: true,
isUserPassword: false,
nbOfCalls: 1,
error: 'an error occured',
});
const randomAlgoanServer: nock.Scope = getFakeAlgoanServer({
baseUrl,
method: 'get',
path: '/',
response: [],
nbOfCalls: 2,
});

await requestBuilder.request({
method: 'GET',
url: '/',
});

expect(oAuthServer.isDone()).toBeFalsy();
expect(randomAlgoanServer.isDone()).toBeFalsy();
expect((requestBuilder as any).accessTokenInstance).toBeDefined();
expect(refreshTokenServer.isDone()).toBeFalsy();

await delay(500);

await requestBuilder.request({
method: 'GET',
url: '/',
});
expect(refreshTokenServer.isDone()).toBeTruthy();
expect(oAuthServer.isDone()).toBeTruthy();
expect(randomAlgoanServer.isDone()).toBeTruthy();
});
});
3 changes: 2 additions & 1 deletion test/utils/fake-server.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const getOAuthServer = (
expiresIn?: number;
refreshExpiresIn?: number;
version?: number;
error?: string;
} = {
baseUrl: 'http://localhost:3000',
isRefreshToken: false,
Expand Down Expand Up @@ -46,7 +47,7 @@ export const getOAuthServer = (
nockInstance = nockInstance.times(params.nbOfCalls);
}

return nockInstance.reply(200, responseBody);
return params.error ? nockInstance.replyWithError(params.error) : nockInstance.reply(200, responseBody);
};

/**
Expand Down

0 comments on commit 5b9df4d

Please sign in to comment.