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
- After a successful OIDC/OAuth flow, the UI writes the JWT into
sessionStorage. sessionStorageis scoped per‑tab and cleared when the tab closes.- Firefox does not propagate the
storageevent forsessionStorage, so new tabs start with an empty store ⇒ forced re‑authentication. - Chrome propagates
localStorageevents, and the UI contains a helper snippet that copies the token between tabs via a temporarylocalStoragekey – but only while the source tab is alive.
How to Reproduce
- Deploy Dependency‑Track (4.11+ tested) with Google OAuth or any OIDC provider.
- Log in with Firefox.
- Press Ctrl+L → Alt+Enter (open current URL in a new tab).
- 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 frontend2. 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 ./distOr 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 Risk | Mitigation |
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 closed | Shorten IdP TTL or add a client‑side inactivity timer |