diff --git a/src/components/auth/AuthController.js b/src/components/auth/AuthController.js
index c9bd451..9eeceb6 100644
--- a/src/components/auth/AuthController.js
+++ b/src/components/auth/AuthController.js
@@ -1,7 +1,9 @@
import mitt from 'mitt';
import UserSession from './UserSession';
-import { userSessionFromCode, renew as auth0Renew } from './oauth2';
+import { userSessionFromCode } from './oauth2';
+
+const STORAGE_KEY = 'taskcluster_user_session';
/**
* Controller for authentication-related pieces of the site.
@@ -21,7 +23,7 @@ export default class AuthController {
this.renewalTimer = null;
window.addEventListener('storage', ({ storageArea, key }) => {
- if (storageArea === localStorage && key === 'userSession') {
+ if (storageArea === localStorage && key === STORAGE_KEY) {
this.loadUserSession();
}
});
@@ -48,7 +50,7 @@ export default class AuthController {
this.renewalTimer = window.setTimeout(() => {
this.renewalTimer = null;
- this.renew({ userSession });
+ this.renew(userSession);
}, timeout);
}
}
@@ -68,7 +70,7 @@ export default class AuthController {
* return the user session.
*/
loadUserSession() {
- const storedUserSession = localStorage.getItem('userSession');
+ const storedUserSession = localStorage.getItem(STORAGE_KEY);
const userSession = storedUserSession
? UserSession.deserialize(storedUserSession)
: null;
@@ -93,9 +95,9 @@ export default class AuthController {
*/
setUserSession = (userSession) => {
if (!userSession) {
- localStorage.removeItem('userSession');
+ localStorage.removeItem(STORAGE_KEY);
} else {
- localStorage.setItem('userSession', userSession.serialize());
+ localStorage.setItem(STORAGE_KEY, userSession.serialize());
}
// localStorage updates do not trigger event listeners on the current window/tab,
@@ -104,14 +106,10 @@ export default class AuthController {
};
/**
- * Renew the user session. This is not possible for all auth methods, and will trivially succeed
- * for methods that do not support it. If it fails, the user will be logged out.
+ * Renew the user session.
+ * This is not currently supported by the Taskcluster OAuth, so we just clean the session
*/
- async renew({ userSession }) {
- try {
- await auth0Renew({ userSession, authController: this });
- } catch (err) {
- this.setUserSession(null);
- }
+ async renew() {
+ this.setUserSession(null);
}
}
diff --git a/src/components/auth/UserSession.js b/src/components/auth/UserSession.js
index 26b069b..c4497a4 100644
--- a/src/components/auth/UserSession.js
+++ b/src/components/auth/UserSession.js
@@ -1,4 +1,5 @@
import { Index } from 'taskcluster-client-web';
+import moment from 'moment';
import { TASKCLUSTER_ROOT_URL } from '../../config';
const USER_ID_REGEX = /mozilla-auth0\/([\w-|]+)\/bugzilla-dashboard-([\w-]+)/;
@@ -31,8 +32,18 @@ export default class UserSession {
Object.assign(this, options);
}
- static fromCredentials(credentials) {
- return new UserSession({ type: 'credentials', email: 'nobody@mozilla.org', credentials });
+ static fromTaskclusterAuth(token, payload) {
+ // Detect when the credentials will expire
+ // And substract 1 minute to fetch new credentials before expiry
+ const expires = moment(payload.expires).subtract(1, 'minute');
+
+ return new UserSession({
+ type: 'credentials',
+ email: 'nobody@mozilla.org',
+ renewToken: token,
+ credentials: payload.credentials,
+ renewAfter: expires,
+ });
}
// determine whether the user changed from old to new; this is used by other components
@@ -52,12 +63,24 @@ export default class UserSession {
// get the user's name
get name() {
return (
- this.fullName
- || (this.credentials && this.credentials.clientId)
+ (this.credentials && this.credentials.clientId)
|| 'unknown'
);
}
+ // Get the expiry date as a nicely formated string
+ get expiresIn() {
+ const diff = moment(this.renewAfter).diff(moment());
+ const duration = moment.duration(diff);
+ if (duration.days() > 0) {
+ return `${duration.days()} days`;
+ }
+ if (duration.hours() > 0) {
+ return `${duration.hours()} hours`;
+ }
+ return `${duration.minutes()} minutes`;
+ }
+
get userId() {
// Find the user ID in Taskcluster credentials
const match = USER_ID_REGEX.exec(this.credentials.clientId);
@@ -75,9 +98,7 @@ export default class UserSession {
// load Taskcluster credentials for this user
getCredentials() {
- return this.credentials
- ? Promise.resolve(this.credentials)
- : this.credentialAgent.getCredentials({});
+ return Promise.resolve(this.credentials);
}
static deserialize(value) {
@@ -85,7 +106,7 @@ export default class UserSession {
}
serialize() {
- return JSON.stringify({ ...this, credentialAgent: undefined });
+ return JSON.stringify({ ...this });
}
getTaskClusterIndexClient = () => new Index({
diff --git a/src/components/auth/oauth2.js b/src/components/auth/oauth2.js
index d437e36..edf5613 100644
--- a/src/components/auth/oauth2.js
+++ b/src/components/auth/oauth2.js
@@ -12,36 +12,15 @@ export function redirectUser() {
// Part 2 - Exchange Oauth code for Taskcluster credentials
export async function userSessionFromCode(url) {
// Get Oauth access token
- const user = await webAuth.code.getToken(url);
+ const token = await webAuth.code.getToken(url);
// Exchange that access token for some Taskcluster credentials
- const request = user.sign({
+ const request = token.sign({
method: 'get',
});
const resp = await fetch(config.OAuth2Options.credentialsUri, request);
const payload = await resp.json();
// Finally build a new user session
- return UserSession.fromCredentials(payload.credentials);
-}
-
-/* eslint-disable consistent-return */
-export async function renew({ userSession }) {
- if (
- !userSession
- || userSession.type !== 'oidc'
- || userSession.oidcProvider !== 'mozilla-auth0'
- ) {
- return;
- }
-
- return new Promise((accept, reject) => webAuth.renewAuth({}, (err, authResult) => {
- if (err) {
- return reject(err);
- } if (!authResult) {
- return reject(new Error('no authResult'));
- }
- // TODO: somehow renew ? Not possible i think with Oauth + TC
- accept();
- }));
+ return UserSession.fromTaskclusterAuth(token.accessToken, payload);
}
diff --git a/src/config.js b/src/config.js
index 382ec33..596a7b3 100644
--- a/src/config.js
+++ b/src/config.js
@@ -14,7 +14,9 @@ const config = {
redirectUri: PRODUCTION ? 'https://bugzilla-management-dashboard.netlify.app' : 'http://localhost:5000',
whitelisted: true,
responseType: 'code',
- maxExpires: '15 minutes',
+ query: {
+ expires: '2 weeks',
+ },
},
productComponentMetrics: 'project/relman/bugzilla-dashboard/product_component_data.json.gz',
reporteesMetrics: 'project/relman/bugzilla-dashboard/reportee_data.json.gz',
diff --git a/src/views/ProfileMenu/index.jsx b/src/views/ProfileMenu/index.jsx
index 82f5b1e..b6ddaf0 100644
--- a/src/views/ProfileMenu/index.jsx
+++ b/src/views/ProfileMenu/index.jsx
@@ -72,6 +72,10 @@ class ProfileMenu extends React.Component {
onClose={this.handleClose}
>
+