diff --git a/src/adapters/authAdapter.test.ts b/src/adapters/authAdapter.test.ts
index a863c21..8ae0953 100644
--- a/src/adapters/authAdapter.test.ts
+++ b/src/adapters/authAdapter.test.ts
@@ -35,7 +35,7 @@ describe('AuthAdapter', () => {
.reply(200);
expect(scope.isDone()).toBe(false);
- await AuthAdapter.login({ ...testCredentials });
+ await AuthAdapter.loginWithEmailPassword({ ...testCredentials });
expect(scope.isDone()).toBe(true);
});
});
diff --git a/src/adapters/authAdapter.ts b/src/adapters/authAdapter.ts
index cee734a..447d936 100644
--- a/src/adapters/authAdapter.ts
+++ b/src/adapters/authAdapter.ts
@@ -6,7 +6,7 @@ type LoginAuthType = {
};
class AuthAdapter extends BaseAdapter {
- static login(params: LoginAuthType) {
+ static loginWithEmailPassword(params: LoginAuthType) {
/* eslint-disable camelcase */
const requestParams = {
...params,
@@ -18,6 +18,19 @@ class AuthAdapter extends BaseAdapter {
return this.prototype.postRequest('oauth/token', { data: requestParams });
}
+
+ static loginWithRefreshToken(refreshToken: string) {
+ /* eslint-disable camelcase */
+ const requestParams = {
+ refresh_token: refreshToken,
+ grant_type: 'refresh_token',
+ client_id: process.env.REACT_APP_API_CLIENT_ID,
+ client_secret: process.env.REACT_APP_API_CLIENT_SECRET,
+ };
+ /* eslint-enable camelcase */
+
+ return this.prototype.postRequest('oauth/token', { data: requestParams });
+ }
}
export default AuthAdapter;
diff --git a/src/constants/index.ts b/src/constants/index.ts
index 3904c7f..2ca62cf 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -1 +1,3 @@
export const PASSWORD_MIN_LENGTH = 5;
+
+export const LOGIN_URL = '/login';
diff --git a/src/helpers/userToken.ts b/src/helpers/userToken.ts
index 44893ec..a3abd6c 100644
--- a/src/helpers/userToken.ts
+++ b/src/helpers/userToken.ts
@@ -1,14 +1,11 @@
-type UserToken =
- | {
- access_token: string;
- refresh_token: string;
- }
- | '{}';
-
-export const getToken = (): UserToken => {
+export const getToken = () => {
return JSON.parse(localStorage.getItem('UserToken') || '{}');
};
-export const setToken = (token: UserToken) => {
+export const setToken = (token: { access_token: string; refresh_token: string }) => {
localStorage.setItem('UserToken', JSON.stringify(token));
};
+
+export const clearToken = () => {
+ localStorage.removeItem('UserToken');
+};
diff --git a/src/lib/requestManager.ts b/src/lib/requestManager.ts
index 81f9b8d..fbecdde 100644
--- a/src/lib/requestManager.ts
+++ b/src/lib/requestManager.ts
@@ -1,5 +1,10 @@
import axios, { Method as HTTPMethod, ResponseType, AxiosRequestConfig, AxiosResponse } from 'axios';
+import AuthAdapter from 'adapters/authAdapter';
+import { setToken, getToken, clearToken } from 'helpers/userToken';
+
+import { LOGIN_URL } from '../constants';
+
export const defaultOptions: { responseType: ResponseType } = {
responseType: 'json',
};
@@ -28,6 +33,56 @@ const requestManager = (
...requestOptions,
};
+ axios.interceptors.request.use(
+ function (config) {
+ const userToken = getToken();
+
+ if (userToken?.access_token) {
+ config.headers.Authorization = `Bearer ${userToken.access_token}`;
+ }
+ return config;
+ },
+ function (error) {
+ return Promise.reject(error);
+ }
+ );
+
+ axios.interceptors.response.use(
+ function (response) {
+ return response;
+ },
+ async function (error) {
+ if (error.response?.status === 401) {
+ const userToken = getToken();
+
+ clearToken();
+
+ if (userToken?.refresh_token) {
+ try {
+ const response = await AuthAdapter.loginWithRefreshToken(userToken.refresh_token);
+
+ const {
+ attributes: { access_token: accessToken, refresh_token: refreshToken },
+ } = await response.data;
+
+ /* eslint-disable camelcase */
+ setToken({ access_token: accessToken, refresh_token: refreshToken });
+ /* eslint-enable camelcase */
+
+ error.config.headers.Authorization = `Bearer ${accessToken}`;
+ return axios.request(error.config);
+ } catch {
+ window.location.href = LOGIN_URL;
+ }
+ }
+
+ window.location.href = LOGIN_URL;
+ }
+
+ return Promise.reject(error);
+ }
+ );
+
return axios.request(requestParams).then((response: AxiosResponse) => {
return response.data;
});
diff --git a/src/screens/Login/index.test.tsx b/src/screens/Login/index.test.tsx
index 12d07fc..f312d59 100644
--- a/src/screens/Login/index.test.tsx
+++ b/src/screens/Login/index.test.tsx
@@ -59,7 +59,7 @@ describe('LoginScreen', () => {
});
test('given an empty email and password in the login form, displays both errors', async () => {
- const mockLogin = jest.spyOn(AuthAdapter, 'login');
+ const mockLogin = jest.spyOn(AuthAdapter, 'loginWithEmailPassword');
render(, { wrapper: BrowserRouter });
@@ -114,7 +114,7 @@ describe('LoginScreen', () => {
});
test('given INCORRECT credentials, displays the error from the API response', async () => {
- const mockLogin = jest.spyOn(AuthAdapter, 'login');
+ const mockLogin = jest.spyOn(AuthAdapter, 'loginWithEmailPassword');
render(, { wrapper: BrowserRouter });
diff --git a/src/screens/Login/index.tsx b/src/screens/Login/index.tsx
index 13c98c0..4bbce98 100644
--- a/src/screens/Login/index.tsx
+++ b/src/screens/Login/index.tsx
@@ -32,7 +32,7 @@ function LoginScreen() {
const performLogin = async () => {
try {
- const response = await AuthAdapter.login({ email: email, password: password });
+ const response = await AuthAdapter.loginWithEmailPassword({ email: email, password: password });
const {
attributes: { access_token: accessToken, refresh_token: refreshToken },