Skip to content

Commit

Permalink
fix: retry failed requests on token refresh
Browse files Browse the repository at this point in the history
  • Loading branch information
Harasz committed May 17, 2022
1 parent c4b9ff0 commit 434e262
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 48 deletions.
8 changes: 7 additions & 1 deletion docs/api/classes/modules_signer.SignerService.md
Expand Up @@ -416,14 +416,20 @@ ___

### publicKeyAndIdentityToken

**publicKeyAndIdentityToken**(): `Promise`<[`IPubKeyAndIdentityToken`](../interfaces/modules_signer.IPubKeyAndIdentityToken.md)\>
**publicKeyAndIdentityToken**(`force?`): `Promise`<[`IPubKeyAndIdentityToken`](../interfaces/modules_signer.IPubKeyAndIdentityToken.md)\>

Generate public key and identity token for authentication purposes.

```typescript
signerService.publicKeyAndIdentityToken();
```

#### Parameters

| Name | Type | Default value | Description |
| :------ | :------ | :------ | :------ |
| `force` | `boolean` | `false` | when true recalculates token even if it is already present |

#### Returns

`Promise`<[`IPubKeyAndIdentityToken`](../interfaces/modules_signer.IPubKeyAndIdentityToken.md)\>
Expand Down
22 changes: 22 additions & 0 deletions docs/api/interfaces/modules_cache_client.AuthTokens.md
@@ -0,0 +1,22 @@
# Interface: AuthTokens

[modules/cache-client](../modules/modules_cache_client.md).AuthTokens

## Table of contents

### Properties

- [refreshToken](modules_cache_client.AuthTokens.md#refreshtoken)
- [token](modules_cache_client.AuthTokens.md#token)

## Properties

### refreshToken

**refreshToken**: `string`

___

### token

**token**: `string`
Expand Up @@ -13,7 +13,7 @@

### did

**did**: `string`
`Optional` **did**: `string`

___

Expand Down
Expand Up @@ -12,4 +12,4 @@

### did

**did**: `string`
`Optional` **did**: `string`
Expand Up @@ -12,4 +12,4 @@

### did

**did**: `string`
`Optional` **did**: `string`
Expand Up @@ -12,4 +12,4 @@

### did

**did**: `string`
`Optional` **did**: `string`
1 change: 1 addition & 0 deletions docs/api/modules/modules_cache_client.md
Expand Up @@ -13,6 +13,7 @@

### Interfaces

- [AuthTokens](../interfaces/modules_cache_client.AuthTokens.md)
- [CacheServerClientOptions](../interfaces/modules_cache_client.CacheServerClientOptions.md)
- [ICacheClient](../interfaces/modules_cache_client.ICacheClient.md)

Expand Down
77 changes: 38 additions & 39 deletions src/modules/cache-client/cache-client.service.ts
Expand Up @@ -21,6 +21,7 @@ import { cacheConfigs } from '../../config/cache.config';
import { ICacheClient } from './cache-client.interface';
import {
AssetsFilter,
AuthTokens,
ClaimsFilter,
TEST_LOGIN_ENDPOINT,
} from './cache-client.types';
Expand Down Expand Up @@ -63,44 +64,43 @@ export class CacheClient implements ICacheClient {
* After authentication runs previously failed requests
*/
async authenticate() {
let tokens: AuthTokens | undefined = undefined;

// First try to refresh access token
try {
const refreshedTokens = await this.refreshToken();

if (refreshedTokens) {
getLogger().debug('[CACHE CLIENT] Setting authorization tokens');
if (!this.isBrowser) {
this._httpClient.defaults.headers.common[
'Authorization'
] = `Bearer ${refreshedTokens.token}`;
}
if (await this.isAuthenticated()) {
this.refresh_token = refreshedTokens.refreshToken;
return;
}
if (refreshedTokens && (await this.isAuthenticated())) {
tokens = refreshedTokens;
}
} catch (error) {
getLogger().error('[CACHE CLIENT] Authentication failed');
getLogger().error(error);
} catch {
getLogger().error('[CACHE CLIENT] Failed to refresh tokens');
}

const pubKeyAndIdentityToken =
await this._signerService.publicKeyAndIdentityToken();
const {
data: { refreshToken, token },
} = await this._httpClient.post<{ token: string; refreshToken: string }>(
'/login',
{
// If refresh token failed or access token is not valid, then sign new identity token
if (!tokens) {
delete this._httpClient.defaults.headers.common['Authorization'];
const pubKeyAndIdentityToken =
await this._signerService.publicKeyAndIdentityToken(true);
const { data } = await this._httpClient.post<AuthTokens>('/login', {
identityToken: pubKeyAndIdentityToken.identityToken,
}
);
});
this.pubKeyAndIdentityToken = pubKeyAndIdentityToken;
tokens = data;
}

// Set new tokens
if (!this.isBrowser) {
this._httpClient.defaults.headers.common[
'Authorization'
] = `Bearer ${token}`;
] = `Bearer ${tokens.token}`;
}
this.refresh_token = refreshToken;
this.pubKeyAndIdentityToken = pubKeyAndIdentityToken;
this.refresh_token = tokens.refreshToken;

// Run previously failed requests
console.log(
`[CACHE CLIENT] Running failed requests: ${this.failedRequests.length}`
);
this.failedRequests = this.failedRequests.filter((callback) => callback());
}

Expand All @@ -113,13 +113,9 @@ export class CacheClient implements ICacheClient {
*/
async handleError(error: AxiosError) {
getLogger().debug(`[CACHE CLIENT] Axios error: ${error.message}`);
getLogger().error(error);
const { config, response } = error;
const originalRequest = config;

getLogger().debug(config);
getLogger().debug(response);

if (
this.authEnabled &&
response &&
Expand All @@ -130,9 +126,18 @@ export class CacheClient implements ICacheClient {
config.url?.indexOf(TEST_LOGIN_ENDPOINT) === -1
) {
getLogger().debug(`[CACHE CLIENT] axios error unauthorized`);
const retryOriginalRequest = new Promise((resolve) => {
const retryOriginalRequest = new Promise((resolve, reject) => {
this.failedRequests.push(() => {
resolve(axios(originalRequest));
axios({
...originalRequest,
headers: {
...originalRequest.headers,
Authorization:
this._httpClient.defaults.headers.common['Authorization'],
},
})
.then(resolve)
.catch(reject);
});
});
if (!this.isAuthenticating) {
Expand Down Expand Up @@ -405,13 +410,7 @@ export class CacheClient implements ICacheClient {
return data;
}

private async refreshToken(): Promise<
| {
token: string;
refreshToken: string;
}
| undefined
> {
private async refreshToken(): Promise<AuthTokens | undefined> {
getLogger().debug('[CACHE CLIENT] Refreshing token');
if (!this.refresh_token) return undefined;

Expand Down
5 changes: 5 additions & 0 deletions src/modules/cache-client/cache-client.types.ts
Expand Up @@ -29,3 +29,8 @@ export enum SearchType {
}

export const TEST_LOGIN_ENDPOINT = '/auth/status';

export interface AuthTokens {
token: string;
refreshToken: string;
}
2 changes: 1 addition & 1 deletion src/modules/did-registry/did.types.ts
Expand Up @@ -32,7 +32,7 @@ export interface ClaimData extends Record<string, unknown> {

export interface GetDIDDocumentOptions {
/* DID of the user */
did: string;
did?: string;

/* Indicates resolving claims object */
includeClaims?: boolean;
Expand Down
8 changes: 5 additions & 3 deletions src/modules/signer/signer.service.ts
Expand Up @@ -442,11 +442,13 @@ export class SignerService {
* ```typescript
* signerService.publicKeyAndIdentityToken();
* ```
*
* @param force when true recalculates token even if it is already present
* @return object with public key and identity token
*/
async publicKeyAndIdentityToken(): Promise<IPubKeyAndIdentityToken> {
if (!this._publicKey || !this._identityToken) {
async publicKeyAndIdentityToken(
force = false
): Promise<IPubKeyAndIdentityToken> {
if (!this._publicKey || !this._identityToken || force) {
await this._calculatePubKeyAndIdentityToken();
}
return {
Expand Down

0 comments on commit 434e262

Please sign in to comment.