Skip to content

Commit

Permalink
feat(api-client): Emit logout event on invalid token/missing cookie f…
Browse files Browse the repository at this point in the history
…rom HttpClient (#3178)
  • Loading branch information
Yserz authored Aug 12, 2020
1 parent f255b1e commit 20e9bbc
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 13 deletions.
8 changes: 5 additions & 3 deletions packages/api-client/src/APIClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
InvalidTokenError,
LoginData,
RegisterData,
MissingCookieError,
} from './auth/';
import {CookieStore} from './auth/CookieStore';
import {BroadcastAPI} from './broadcast/';
Expand Down Expand Up @@ -137,11 +138,12 @@ export class APIClient extends EventEmitter {
const httpClient = new HttpClient(this.config.urls.rest, this.accessTokenStore);
const webSocket = new WebSocketClient(this.config.urls.ws, httpClient);

webSocket.on(WebSocketClient.TOPIC.ON_INVALID_TOKEN, async error => {
this.logger.warn(`Cannot renew access token because cookie is invalid: ${error.message}`, error);
const onInvalidCredentials = async (error: InvalidTokenError | MissingCookieError) => {
await this.logout();
this.emit(APIClient.TOPIC.ON_LOGOUT, error);
});
};
webSocket.on(WebSocketClient.TOPIC.ON_INVALID_TOKEN, onInvalidCredentials);
httpClient.on(HttpClient.TOPIC.ON_INVALID_TOKEN, onInvalidCredentials);

this.transport = {
http: httpClient,
Expand Down
12 changes: 11 additions & 1 deletion packages/api-client/src/http/HttpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,19 @@ import {PriorityQueue} from '@wireapp/priority-queue';
import axios, {AxiosError, AxiosRequestConfig, AxiosResponse} from 'axios';
import {EventEmitter} from 'events';
import logdown from 'logdown';
import {AccessTokenData, AccessTokenStore, AuthAPI} from '../auth/';
import {AccessTokenData, AccessTokenStore, AuthAPI, InvalidTokenError, MissingCookieError} from '../auth/';
import {BackendErrorMapper, ConnectionState, ContentType, NetworkError, StatusCode} from '../http/';
import {ObfuscationUtil} from '../obfuscation/';
import {sendRequestWithCookie} from '../shims/node/cookie';

enum TOPIC {
ON_CONNECTION_STATE_CHANGE = 'HttpClient.TOPIC.ON_CONNECTION_STATE_CHANGE',
ON_INVALID_TOKEN = 'HttpClient.TOPIC.ON_INVALID_TOKEN',
}

export interface HttpClient {
on(event: TOPIC.ON_CONNECTION_STATE_CHANGE, listener: (state: ConnectionState) => void): this;
on(event: TOPIC.ON_INVALID_TOKEN, listener: (error: InvalidTokenError | MissingCookieError) => void): this;
}

export class HttpClient extends EventEmitter {
Expand Down Expand Up @@ -129,6 +131,14 @@ export class HttpClient extends EventEmitter {

if (isBackendError) {
error = BackendErrorMapper.map(errorData);
if (error instanceof InvalidTokenError || error instanceof MissingCookieError) {
// On invalid cookie the application is supposed to logout.
this.logger.warn(
`[HTTP Client] Cannot renew access token because cookie/token is invalid: ${error.message}`,
error,
);
this.emit(HttpClient.TOPIC.ON_INVALID_TOKEN, error);
}
} else {
const isUnauthorized = errorStatus === StatusCode.UNAUTHORIZED;
const hasAccessToken = !!this.accessTokenStore?.accessToken;
Expand Down
20 changes: 11 additions & 9 deletions packages/api-client/src/tcp/WebSocketClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import {EventEmitter} from 'events';
import logdown from 'logdown';
import {CloseEvent, ErrorEvent, Event} from 'reconnecting-websocket';

import {InvalidTokenError} from '../auth/';
import {BackendErrorMapper, HttpClient, NetworkError} from '../http/';
import {InvalidTokenError, MissingCookieError} from '../auth/';
import {HttpClient, NetworkError} from '../http/';
import {Notification} from '../notification/';
import {ReconnectingWebsocket, WEBSOCKET_STATE} from './ReconnectingWebsocket';

Expand All @@ -35,7 +35,7 @@ enum TOPIC {

export interface WebSocketClient {
on(event: TOPIC.ON_ERROR, listener: (error: Error | ErrorEvent) => void): this;
on(event: TOPIC.ON_INVALID_TOKEN, listener: (error: InvalidTokenError) => void): this;
on(event: TOPIC.ON_INVALID_TOKEN, listener: (error: InvalidTokenError | MissingCookieError) => void): this;
on(event: TOPIC.ON_MESSAGE, listener: (notification: Notification) => void): this;
on(event: TOPIC.ON_STATE_CHANGE, listener: (state: WEBSOCKET_STATE) => void): this;
}
Expand Down Expand Up @@ -154,13 +154,15 @@ export class WebSocketClient extends EventEmitter {
} catch (error) {
if (error instanceof NetworkError) {
this.logger.warn(error);
} else {
const mappedError = BackendErrorMapper.map(error);
// On invalid token the WebSocket is supposed to get closed by the client
this.emit(
error instanceof InvalidTokenError ? WebSocketClient.TOPIC.ON_INVALID_TOKEN : WebSocketClient.TOPIC.ON_ERROR,
mappedError,
} else if (error instanceof InvalidTokenError || error instanceof MissingCookieError) {
// On invalid cookie the application is supposed to logout.
this.logger.warn(
`[WebSocket] Cannot renew access token because cookie/token is invalid: ${error.message}`,
error,
);
this.emit(WebSocketClient.TOPIC.ON_INVALID_TOKEN, error);
} else {
this.emit(WebSocketClient.TOPIC.ON_ERROR, error);
}
} finally {
this.isRefreshingAccessToken = false;
Expand Down

0 comments on commit 20e9bbc

Please sign in to comment.