From b42c3efd5a9e2ed9c96e3619037a55f22e47b0bf Mon Sep 17 00:00:00 2001 From: David Lyon <5115845+dauglyon@users.noreply.github.com> Date: Tue, 7 Jul 2026 12:45:50 -0700 Subject: [PATCH] Remove hardcoded 14-day token lifetime from auth cookie handling setCookie fell back to a hardcoded DEFAULT_TOKEN_LIFE of 14 days when no expiration was supplied. With the login token lifetime moving from two weeks to four weeks, that fallback would silently keep cookies at the old 14-day value. The production login and logout paths already pass an explicit expires sourced from the auth service, so they are unaffected. The only caller relying on the fallback was the localhost dev token-injection dialog. - Remove DEFAULT_TOKEN_LIFE and require an integer expires in setCookie (throws otherwise), so cookie expiry must always come from the auth service rather than a hardcoded client-side lifetime. - Dev token-injection dialog now fetches the token's real expiration via getTokenInfo and passes it through; invalid tokens are reported. - Update authSpec setCookie call to pass an explicit expires. --- kbase-extension/static/kbase/js/api/auth.js | 23 ++++++++++--------- .../static/kbase/js/narrativeLogin.js | 17 ++++++++++++-- test/unit/spec/api/authSpec.js | 1 + 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/kbase-extension/static/kbase/js/api/auth.js b/kbase-extension/static/kbase/js/api/auth.js index 15d37fa022..6107187885 100644 --- a/kbase-extension/static/kbase/js/api/auth.js +++ b/kbase-extension/static/kbase/js/api/auth.js @@ -24,19 +24,18 @@ define(['bluebird', 'jquery', 'narrativeConfig'], (Promise, $, Config) => { }, }; - const DEFAULT_TOKEN_LIFE = 14 * 24 * 60 * 60 * 1000; // millis - /** * Meant for managing auth or session cookies (mainly auth cookies as set by * a developer working locally - which is why this is very very simple). * Get a cookie "object" (key-value pairs) as input. - * If it's missing name or value, does nothing. - * Default expiration time is 14 days. - * domain, expires, and max-age are optional - * expires is expected to be the timestamp (ms since epoch) it will expire + * If it's missing name, does nothing. + * expires is REQUIRED and is expected to be the timestamp (ms since epoch) + * at which the cookie expires. It must be sourced from the auth service + * (a token's real expiration) rather than a hardcoded client-side lifetime, + * so the cookie always tracks the actual token lifetime. + * domain and max-age are optional. * default fields are: * - path = '/' - * - expires = now + 14 days * @param {object} cookie * - has the cookie keys: name, value, path, expires, max-age, domain * - adds secure=true, samesite=Lax for KBase use. @@ -47,16 +46,18 @@ define(['bluebird', 'jquery', 'narrativeConfig'], (Promise, $, Config) => { if (!cookie.name) { return; } + if (!Number.isInteger(cookie.expires)) { + throw new Error( + 'setCookie requires an integer `expires` (ms since epoch) sourced from the auth service' + ); + } const name = encodeURIComponent(cookie.name); const value = encodeURIComponent(cookie.value || ''); const props = { - expires: Date.now() + DEFAULT_TOKEN_LIFE, // gets translated to GMT string + expires: cookie.expires, // gets translated to GMT string path: '/', samesite: 'Lax', }; - if (Number.isInteger(cookie.expires)) { - props.expires = cookie.expires; - } // Default to secure cookies global setting if not specified. if (typeof cookie.secure === 'undefined') { diff --git a/kbase-extension/static/kbase/js/narrativeLogin.js b/kbase-extension/static/kbase/js/narrativeLogin.js index c96111ee8f..74cf9e8f07 100644 --- a/kbase-extension/static/kbase/js/narrativeLogin.js +++ b/kbase-extension/static/kbase/js/narrativeLogin.js @@ -80,14 +80,27 @@ define([ buttons: [ $('') .append('OK') - .click(() => { - dialog.hide(); + .click(async () => { const newToken = $inputField.val(); + // Look up the token's real expiration from the auth service + // rather than assuming a fixed lifetime, so the dev cookie + // matches the actual token lifetime. + let tokenInfo; + try { + tokenInfo = await authClient.getTokenInfo(newToken); + } catch (error) { + alert( + 'That auth token could not be validated against the auth service. Please check the token and try again.' + ); + return; + } + dialog.hide(); authClient.setCookie({ name: 'kbase_session', value: newToken, domain: 'localhost', secure: false, + expires: tokenInfo.expires, }); location.reload(); }), diff --git a/test/unit/spec/api/authSpec.js b/test/unit/spec/api/authSpec.js index 25cca20c31..5ee3f9a958 100644 --- a/test/unit/spec/api/authSpec.js +++ b/test/unit/spec/api/authSpec.js @@ -451,6 +451,7 @@ define(['api/auth', 'narrativeConfig', 'uuid', 'testUtil'], (Auth, Config, Uuid, name: backupCookieName, value: backupCookieValue, domain: 'localhost', + expires: Date.now() + 14 * 1000 * 60 * 60 * 24, }); // The backup cookie should be set.