Files
edx-platform/lms/static/js/jwt_auth/AxiosJwtTokenService.js
Syed Ali Abbas Zaidi 8480dbc228 chore: apply amnesty on existing not fixable issues (#32215)
* fix: eslint operator-linebreak issue

* fix: eslint quotes issue

* fix: react jsx indent and props issues

* fix: eslint trailing spaces issues

* fix: eslint line around directives issue

* fix: eslint semi rule

* fix: eslint newline per chain rule

* fix: eslint space infix ops rule

* fix: eslint space-in-parens issue

* fix: eslint space before function paren issue

* fix: eslint space before blocks issue

* fix: eslint arrow body style issue

* fix: eslint dot-location issue

* fix: eslint quotes issue

* fix: eslint quote props issue

* fix: eslint operator assignment issue

* fix: eslint new line after import issue

* fix: indent issues

* fix: operator assignment issue

* fix: all autofixable eslint issues

* fix: all react related fixable issues

* fix: autofixable eslint issues

* chore: remove all template literals

* fix: remaining autofixable issues

* chore: apply amnesty on all existing issues

* fix: failing xss-lint issues

* refactor: apply amnesty on remaining issues

* refactor: apply amnesty on new issues

* fix: remove file level suppressions

* refactor: apply amnesty on new issues
2023-08-07 19:13:19 +05:00

127 lines
4.5 KiB
JavaScript

/**
* Service class to support JWT Token Authentication.
*
* Temporarily copied from the edx/frontend-platform
*/
import Cookies from 'universal-cookie';
import jwtDecode from 'jwt-decode';
import axios from 'axios';
import createRetryInterceptor from './interceptors/createRetryInterceptor';
import { processAxiosErrorAndThrow } from './utils';
export default class AxiosJwtTokenService {
static isTokenExpired(token) {
return !token || token.exp < Date.now() / 1000;
}
constructor(tokenCookieName, tokenRefreshEndpoint) {
this.tokenCookieName = tokenCookieName;
this.tokenRefreshEndpoint = tokenRefreshEndpoint;
this.httpClient = axios.create();
// Set withCredentials to true. Enables cross-site Access-Control requests
// to be made using cookies, authorization headers or TLS client
// certificates. More on MDN:
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
this.httpClient.defaults.withCredentials = true;
// Add retries to this axios instance
this.httpClient.interceptors.response.use(
response => response,
createRetryInterceptor({ httpClient: this.httpClient }),
);
this.cookies = new Cookies();
this.refreshRequestPromises = {};
}
getHttpClient() {
return this.httpClient;
}
decodeJwtCookie() {
const cookieValue = this.cookies.get(this.tokenCookieName);
if (cookieValue) {
try {
return jwtDecode(cookieValue);
} catch (e) {
const error = Object.create(e);
error.message = 'Error decoding JWT token';
error.customAttributes = { cookieValue };
throw error;
}
}
return null;
}
refresh() {
if (this.refreshRequestPromises[this.tokenCookieName] === undefined) {
const makeRefreshRequest = async () => {
let axiosResponse;
try {
try {
axiosResponse = await this.httpClient.post(this.tokenRefreshEndpoint);
} catch (error) {
processAxiosErrorAndThrow(error);
}
} catch (error) {
const userIsUnauthenticated = error.response && error.response.status === 401;
if (userIsUnauthenticated) {
// Clean up the cookie if it exists to eliminate any situation
// where the cookie is not expired but the jwt is expired.
this.cookies.remove(this.tokenCookieName);
const decodedJwtToken = null;
return decodedJwtToken;
}
// TODO: Network timeouts and other problems will end up in
// this block of code. We could add logic for retrying token
// refreshes if we wanted to.
throw error;
}
const decodedJwtToken = this.decodeJwtCookie();
if (!decodedJwtToken) {
// This is an unexpected case. The refresh endpoint should
// set the cookie that is needed. See ARCH-948 for more
// information on a similar situation that was happening
// prior to this refactor in Oct 2019.
const error = new Error('Access token is still null after successful refresh.');
error.customAttributes = { axiosResponse };
throw error;
}
return decodedJwtToken;
};
this.refreshRequestPromises[this.tokenCookieName] = makeRefreshRequest().finally(() => {
delete this.refreshRequestPromises[this.tokenCookieName];
});
}
return this.refreshRequestPromises[this.tokenCookieName];
}
async getJwtToken() {
// eslint-disable-next-line no-useless-catch
try {
const decodedJwtToken = this.decodeJwtCookie(this.tokenCookieName);
if (!AxiosJwtTokenService.isTokenExpired(decodedJwtToken)) {
return decodedJwtToken;
}
} catch (e) {
// Log unexpected error and continue with attempt to refresh it.
throw e;
}
// eslint-disable-next-line no-useless-catch
try {
return await this.refresh();
} catch (e) {
throw e;
}
}
}