I am fairly new to React. This question is related to storing the authentication token in the client side and reusing it until expiry.
I am using MSAL to for authentication in my React app. Below is my code.
import * as React from 'react';
import {AuthOptions, CacheOptions, SystemOptions} from './MsalConfig';
import { UserAgentApplication } from 'msal';
//export const authContext: AuthenticationContext = new AuthenticationContext(msalConfig);
export const msalInstance = new UserAgentApplication({
auth: AuthOptions,
cache: CacheOptions,
system: SystemOptions
});
export const withAuth = function(WrappedComponent){
return class Auth extends React.Component{
constructor(props) {
super(props);
this.state = {
authenticated: false,
renewIframe: false,
hasError: false,
errorMessage: null,
graphAPIToken: null
};
}
componentWillMount() {
this.checkAuthentication();
}
checkAuthentication = () => {
if(this.state.graphAPIToken == null){
// action to perform on authentication
msalInstance.handleRedirectCallback(() => { // on success
this.setState({
authenticated: true
});
}, (authErr, accountState) => { // on fail
console.log("Error after graph API call " + authErr);
this.setState({
hasError: true,
errorMessage: authErr.errorMessage
});
});
// if we are inside renewal callback (hash contains access token), do nothing
if (msalInstance.isCallback(window.location.hash)) {
this.setState({
renewIframe: true
});
return;
}
// not logged in, perform full page redirect
if (!msalInstance.getAccount()) {
msalInstance.loginRedirect({});
return;
} else { // logged in, set authenticated state
this.setState({
authenticated: true
}, () => {
this.getAccessToken(msalInstance);
});
}
}
}
getAccessToken = (msalInstance) => {
console.log(msalInstance);
// if the user is already logged in you can acquire a token
if (msalInstance.getAccount()) {
var tokenRequest = {
scopes: ["user.read"]
};
msalInstance.acquireTokenSilent(tokenRequest)
.then(response => {
// get access token from response
// response.accessToken
console.log(response.accessToken);
this.setState({
graphAPIToken: response.accessToken
});
//return response.accessToken;
})
.catch(err => {
// could also check if err instance of InteractionRequiredAuthError if you can import the class.
if (err.name === "InteractionRequiredAuthError") {
return msalInstance.acquireTokenPopup(tokenRequest)
.then(response => {
// get access token from response
// response.accessToken
console.log(response.accessToken);
this.setState({
graphAPIToken: response.accessToken
});
//return response.accessToken;
})
.catch(err => {
console.log("Error inside getAccessToken " + err);
});
}
console.log("Error inside getAccessToken " + err);
});
} else {
// user is not logged in, you will need to log them in to acquire a token
console.log("u aren't logged in");
}
}
callGraphAPI = (token) => {
//..
}
render(){
if (this.state.renewIframe) {
return <div>hidden renew iframe - not visible</div>;
}
if (this.state.authenticated) {
return <WrappedComponent {...this.props} />;
}
if (this.state.hasError) {
console.log("Login error: " + this.state.errorMessage);
}
console.log("Login error: " + this.state.errorMessage);
}
};
}
Now, I am using this in my React routes in my index.js
:
ReactDOM.render(<MuiThemeProvider theme={theme}>
<Router>
<Switch>
<Route path="/" exact component={(withAuth)(Projects)}/>
<Route path="/signin" exact component={SignIn}/>
<Route path="/projects" exact component={(withAuth)(Projects)}/>
<Route path="/admin" exact component={(withAuth)(Admin)}/>
<Route path="/projectstages/:projectNumber" exact component={(withAuth)(ProjectStages)}/>
<Route path="/formspage" exact component={(withAuth)(FormsPage)}/>
<Route path="/users" exact component={(withAuth)(UserManagement)}/>
</Switch>
</Router>
</MuiThemeProvider>, document.getElementById('root'));
Whenever I access any URL, the componentWillMount
of withAuth
component will get called to check the authentication. How do I make sure that the token is generated only once and stored in the cache and reuse it until it expires? Also, I am not sure if I have implemented the authentication in correct way. Any help with this please?