107 lines
3.0 KiB
JavaScript
107 lines
3.0 KiB
JavaScript
|
|
import auth0 from 'auth0-js';
|
||
|
|
import {
|
||
|
|
storeStateAndNonce,
|
||
|
|
clearStateAndNonce,
|
||
|
|
getStateAndNonce,
|
||
|
|
storeAuth,
|
||
|
|
getIdToken,
|
||
|
|
getUserInfo,
|
||
|
|
clear,
|
||
|
|
getExpiresAt,
|
||
|
|
} from './storage';
|
||
|
|
|
||
|
|
export default class AuthenticationClient {
|
||
|
|
/**
|
||
|
|
* Instantiates an authentication client.
|
||
|
|
* You should only need one per app and authentication method.
|
||
|
|
* @param {Object} auth0Config An auth0 configuration object, as per their API.
|
||
|
|
*/
|
||
|
|
constructor(auth0Config) {
|
||
|
|
this.config = auth0Config;
|
||
|
|
this.webAuth = new auth0.WebAuth(auth0Config);
|
||
|
|
}
|
||
|
|
|
||
|
|
logout() {
|
||
|
|
clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
getUserInfo() {
|
||
|
|
return getUserInfo();
|
||
|
|
}
|
||
|
|
|
||
|
|
isAuthenticated() {
|
||
|
|
return !!getIdToken();
|
||
|
|
}
|
||
|
|
|
||
|
|
isExpired() {
|
||
|
|
const expiresAt = getExpiresAt();
|
||
|
|
return new Date().getTime() > expiresAt && this.isAuthenticated();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Triggers a login by redirecting to auth0.
|
||
|
|
*/
|
||
|
|
triggerLogin(state) {
|
||
|
|
// clear the state and nonce when triggering a login - otherwise hash parsing wont work.
|
||
|
|
clearStateAndNonce();
|
||
|
|
this.webAuth.authorize({ state: JSON.stringify(state) });
|
||
|
|
}
|
||
|
|
|
||
|
|
triggerSilentLogin(state) {
|
||
|
|
if (!state) {
|
||
|
|
throw new Error('You must specify a state.');
|
||
|
|
}
|
||
|
|
const nonce = new Date().getTime().toString();
|
||
|
|
// before we trigger the silent login - store the state and nonce in localstorage.
|
||
|
|
storeStateAndNonce(state, nonce);
|
||
|
|
|
||
|
|
let url = this.webAuth.client.buildAuthorizeUrl({
|
||
|
|
...this.config,
|
||
|
|
nonce,
|
||
|
|
state: JSON.stringify(state),
|
||
|
|
});
|
||
|
|
url += '&prompt=none';
|
||
|
|
window.location.href = url;
|
||
|
|
}
|
||
|
|
|
||
|
|
storeSession(authResult, resolve, reject) {
|
||
|
|
this.webAuth.client.userInfo(authResult.accessToken, (err, user) => {
|
||
|
|
if (err) {
|
||
|
|
// if any error happens when fetching user info - nuke all session info
|
||
|
|
this.logout();
|
||
|
|
return reject('Authentication failed');
|
||
|
|
}
|
||
|
|
const expiresAt = JSON.stringify(authResult.expiresIn * 1000 + new Date().getTime());
|
||
|
|
storeAuth({ ...authResult, user, expiresAt });
|
||
|
|
return resolve(JSON.parse(authResult.state));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
handleAuthentication() {
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
// retrieve stored state and nonce from localstorage
|
||
|
|
const { state, nonce } = getStateAndNonce();
|
||
|
|
// however, if there is no state and nonce stored - do not provide any param to parseHash.
|
||
|
|
// Otherwise, the non-silent logins will fail due to invalid state.
|
||
|
|
const parseHashParam = state && nonce ? { state, nonce } : undefined;
|
||
|
|
|
||
|
|
this.webAuth.parseHash(parseHashParam, (err, authResult) => {
|
||
|
|
if (authResult && authResult.accessToken && authResult.idToken) {
|
||
|
|
// If we fail to either set the session or store user info - reject and clear the session.
|
||
|
|
try {
|
||
|
|
return this.storeSession(authResult, resolve, reject);
|
||
|
|
} catch (error) {
|
||
|
|
return reject(error || 'Authentication failed');
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
return reject(err || 'Authentication failed');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
idToken() {
|
||
|
|
return getIdToken();
|
||
|
|
}
|
||
|
|
}
|