Skip to content

Commit

Permalink
Merge pull request #36 from Five-Fishes/refresh-token
Browse files Browse the repository at this point in the history
Refresh token
  • Loading branch information
HowardYaw authored Mar 14, 2021
2 parents 790bdae + 0c013a0 commit 39ebb65
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 27 deletions.
13 changes: 7 additions & 6 deletions src/main/webapp/app/config/axios-interceptor.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import axios from 'axios';
import { getBasePath, Storage } from 'react-jhipster';

import { SERVER_API_URL, AUTH_TOKEN_KEY } from 'app/config/constants';
import { SERVER_API_URL, ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY } from 'app/config/constants';

const TIMEOUT = 1 * 60 * 1000;
axios.defaults.timeout = TIMEOUT;
axios.defaults.baseURL = SERVER_API_URL;

function setupAxiosInterceptors(onUnauthenticated: () => void) {
function setupAxiosInterceptors(onUnauthenticated: () => Promise<void>) {
const onRequestSuccess = config => {
const token = Storage.local.get(AUTH_TOKEN_KEY) || Storage.session.get(AUTH_TOKEN_KEY);
const token = Storage.local.get(ACCESS_TOKEN_KEY) || Storage.session.get(ACCESS_TOKEN_KEY);
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
};
const onResponseSuccess = response => response;
const onResponseError = err => {
const onResponseError = async err => {
const status = err.status || (err.response ? err.response.status : 0);
if (status === 401) {
onUnauthenticated();
await onUnauthenticated();
return;
}
return Promise.reject(err);
throw err;
};
axios.interceptors.request.use(onRequestSuccess);
axios.interceptors.response.use(onResponseSuccess, onResponseError);
Expand Down
3 changes: 2 additions & 1 deletion src/main/webapp/app/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export const APP_WHOLE_NUMBER_FORMAT = '0,0';
export const APP_TWO_DIGITS_AFTER_POINT_NUMBER_FORMAT = '0,0.[00]';

export const FIREBASE_AUTH_HEADER_NAME = 'X-Authorization-Firebase';
export const AUTH_TOKEN_KEY = 'authToken';
export const ACCESS_TOKEN_KEY = 'accessToken';
export const REFRESH_TOKEN_KEY = 'refreshToken';
export const FIREBASE_TOKEN_KEY = 'firebaseToken';
6 changes: 3 additions & 3 deletions src/main/webapp/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import setupAxiosInterceptors from './config/axios-interceptor';
import ErrorBoundary from './shared/error/error-boundary';
import AppComponent from './app';
import { loadIcons } from './config/icon-loader';
import { AUTH_TOKEN_KEY, FIREBASE_TOKEN_KEY } from 'app/config/constants';
import { logout } from './shared/services/auth.service';
import { ACCESS_TOKEN_KEY, FIREBASE_TOKEN_KEY } from 'app/config/constants';
import { handleUnauthenticated } from './shared/services/auth.service';

const devTools = process.env.NODE_ENV === 'development' ? <DevTools /> : null;

registerLocale(store);
setupAxiosInterceptors(logout);
setupAxiosInterceptors(handleUnauthenticated);
loadIcons();

const rootEl = document.getElementById('root');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Redirect, RouteComponentProps, Link } from 'react-router-dom';
import { IRootState } from 'app/shared/reducers';
import { CardImg, Container, Button, Row, Col } from 'reactstrap';
import { AvForm, AvField } from 'availity-reactstrap-validation';
import { emailLogin, fetchAccount, getAuthToken } from 'app/shared/services/auth.service';
import { emailLogin, getAuthToken } from 'app/shared/services/auth.service';
import { toast } from 'react-toastify';

export interface IAuthEmailLoginProps extends StateProps, RouteComponentProps<{}> {}
Expand All @@ -29,7 +29,6 @@ export class AuthEmailLogin extends React.Component<IAuthEmailLoginProps, IAuthE
});
emailLogin(values)
.then(firebaseToken => getAuthToken(firebaseToken))
.then(() => fetchAccount())
.then(() => {
toast.success('Login Successfully');
this.props.history.push('/');
Expand Down
4 changes: 1 addition & 3 deletions src/main/webapp/app/modules/auth/login/auth-login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { CardImg, Container, Button, Row, Col } from 'reactstrap';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import firebase from 'firebase';
import { toast } from 'react-toastify';
import { fetchAccount, getAuthToken, socialLogin } from 'app/shared/services/auth.service';
import { getAuthToken, socialLogin } from 'app/shared/services/auth.service';

export interface IAuthLoginProps extends StateProps, RouteComponentProps<{}> {}

Expand All @@ -35,7 +35,6 @@ export class AuthLogin extends React.Component<IAuthLoginProps> {
async handleGoogleLogin() {
socialLogin('google')
.then(firebaseToken => getAuthToken(firebaseToken))
.then(() => fetchAccount())
.then(() => toast.success('Login Successfully'))
.catch(error => {
const firebaseError = error as firebase.FirebaseError;
Expand All @@ -47,7 +46,6 @@ export class AuthLogin extends React.Component<IAuthLoginProps> {
handleFacebookLogin() {
socialLogin('facebook')
.then(firebaseToken => getAuthToken(firebaseToken))
.then(() => fetchAccount())
.then(() => toast.success('Login Successfully'))
.catch(error => {
const firebaseError = error as firebase.FirebaseError;
Expand Down
4 changes: 4 additions & 0 deletions src/main/webapp/app/shared/model/auth/auth-token.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface IAuthToken {
accessToken: String;
refreshToken: String;
}
6 changes: 0 additions & 6 deletions src/main/webapp/app/shared/reducers/authentication.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export const ACTION_TYPES = {
LOGIN: 'authentication/LOGIN',
LOGOUT: 'authentication/LOGOUT',
FETCH_ACCOUNT: 'authentication/FETCH_ACCOUNT'
};
Expand Down Expand Up @@ -28,11 +27,6 @@ const initialState: IAuthenticationInitialState = {

export default (state: IAuthenticationInitialState = initialState, action): IAuthenticationInitialState => {
switch (action.type) {
case ACTION_TYPES.LOGIN:
return {
...state,
isAuthenticated: true
};
case ACTION_TYPES.LOGOUT:
return {
...state,
Expand Down
32 changes: 26 additions & 6 deletions src/main/webapp/app/shared/services/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,49 @@
import axios from 'axios';
import { Storage } from 'react-jhipster';
import { firebaseAuth, firebaseGoogleAuthProvider, firebaseFacebookAuthProvider } from 'app/config/firebase';
import { FIREBASE_AUTH_HEADER_NAME, AUTH_TOKEN_KEY, FIREBASE_TOKEN_KEY } from 'app/config/constants';
import { FIREBASE_AUTH_HEADER_NAME, ACCESS_TOKEN_KEY, FIREBASE_TOKEN_KEY, REFRESH_TOKEN_KEY } from 'app/config/constants';
import store from 'app/config/store';
import { ACTION_TYPES } from '../reducers/authentication';
import { ILogin } from '../model/auth/login.model';
import { IAuthToken } from '../model/auth/auth-token.model';

export async function getAuthToken(firebaseToken: string): Promise<void> {
const headers = {
[FIREBASE_AUTH_HEADER_NAME]: firebaseToken
};
const response = await axios.post('/api/firebase/authenticate', null, {
const response = await axios.post('/api/authenticate/firebase', null, {
headers
});
const jwtToken: string = response.data['id_token'];
Storage.local.set(AUTH_TOKEN_KEY, jwtToken);
store.dispatch({ type: ACTION_TYPES.LOGIN });
const responseBody: IAuthToken = response.data;
Storage.local.set(ACCESS_TOKEN_KEY, responseBody.accessToken);
Storage.local.set(REFRESH_TOKEN_KEY, responseBody.refreshToken);
await fetchAccount();
}

export function logout(): void {
Storage.local.remove(FIREBASE_TOKEN_KEY);
Storage.local.remove(AUTH_TOKEN_KEY);
Storage.local.remove(ACCESS_TOKEN_KEY);
Storage.local.remove(REFRESH_TOKEN_KEY);
store.dispatch({ type: ACTION_TYPES.LOGOUT });
}

export async function handleUnauthenticated(): Promise<void> {
const refreshToken = Storage.local.get(REFRESH_TOKEN_KEY) || Storage.session.get(REFRESH_TOKEN_KEY);
if (refreshToken) {
let response = null;
try {
response = await axios.post(`/api/authenticate/refresh?refreshToken=${refreshToken}`);
} catch (err) {
logout();
throw err;
}
const responseBody: IAuthToken = response.data;
Storage.local.set(ACCESS_TOKEN_KEY, responseBody.accessToken);
Storage.local.set(REFRESH_TOKEN_KEY, responseBody.refreshToken);
await fetchAccount();
}
}

const SocialProvider = {
facebook: firebaseFacebookAuthProvider,
google: firebaseGoogleAuthProvider
Expand Down

0 comments on commit 39ebb65

Please sign in to comment.