Dependency Track: fixing the re-login on new tab problem

Hi everyone! I’d like to introduce a new type of post on my blog—Dev Notes. These posts are closely tied to my current work and cover day-to-day routines, problem-solving, feature delivery, and other software-development topics.

Today’s post is about a session issue in Dependency-Track that forces you to re-login when you open a new tab (especially in Firefox) and how to fix it.

Dependency‑Track’s front‑end stores the OAuth access token in sessionStorage, which is tab‑scoped storage. This is intended behaviour and positioned as a security feature, but it’s not comfortable in use. In Firefox, this always forces a fresh login when you open the application in another tab. Chrome partially masks the problem by syncing the token between open tabs with a localStorage broadcast hack, but the moment you close the original tab, the session evaporates.

Root Cause

  1. After a successful OIDC/OAuth flow, the UI writes the JWT into sessionStorage.
  2. sessionStorage is scoped per‑tab and cleared when the tab closes.
  3. Firefox does not propagate the storage event for sessionStorage, so new tabs start with an empty store ⇒ forced re‑authentication.
  4. Chrome propagates localStorage events, and the UI contains a helper snippet that copies the token between tabs via a temporary localStorage key – but only while the source tab is alive.

How to Reproduce

  1. Deploy Dependency‑Track (4.11+ tested) with Google OAuth or any OIDC provider.
  2. Log in with Firefox.
  3. Press Ctrl+L → Alt+Enter (open current URL in a new tab).
  4. The new tab loops back to /login.

Solution

Move the token to localStorage

1. Clone the UI repository

git clone https://github.com/DependencyTrack/frontend.git
cd frontend

2. Replace sessionStorage with localStorage

Edit every place that reads/writes the token (currently src/services/AuthService.ts and src/store/modules/auth.ts).

- window.sessionStorage.setItem(TOKEN_KEY, token);
+ window.localStorage.setItem(TOKEN_KEY, token);
- const token = window.sessionStorage.getItem(TOKEN_KEY);
+ const token = window.localStorage.getItem(TOKEN_KEY);

3. Re‑build the UI

npm ci
npm run build  # outputs ./dist

Or via Docker:

docker build -t dtrack-frontend-localstorage .

4. Deploy your custom image

  • Helm: set ui.image.repository=dtrack-frontend-localstorage.
  • Docker‑Compose: change the image: line for the UI service.

5. Verify

  • Repeat the reproduction steps – the dashboard now loads without re‑auth in every new tab.
  • Close all tabs and open a fresh one – the session persists until the token itself expires.

Security Considerations

Potential RiskMitigation
localStorage is readable by any JS running on the origin (XSS)Enforce a strict CSP, enable SRI, keep Dependency‑Track up to date
Token persists after all tabs are closedShorten IdP TTL or add a client‑side inactivity timer

Avatar photo
Dmitry Protsenko

Senior Software Engineer
Specialized on Java / Kotlin and CyberSecurity
Author of this blog

Articles: 34