accessToken follow-upDate: 2026-10-28
Related symptom: after login (or later on the dashboard), localStorage.accessToken becomes the string "undefined", white blank screen, user cannot logout until local storage is cleared. Worse with WAF blocking mode; usually fine when blocking is off.
/api/login and /api/refresh-token (and iAM Smart login APIs) must return untouched JSON from the backend in blocking mode, with a real JWT in accessToken / refreshToken.
The WAF must not:
accessToken fieldFrontend changes stop a permanent stuck white screen:
atob on - / _)"undefined" access token/login when token is unusableApp mitigation does not make a WAF-damaged response succeed. WAF/LB still needs tuning so login/refresh return a real JWT.
Base context path: /api (see backend application.yml).
| Purpose | Method | Path (after host) |
|---|---|---|
| Password login | POST | /api/login |
| Refresh token | POST | /api/refresh-token |
| Logout | POST | /api/logout |
| iAM Smart login | POST | /api/smart/login |
| iAM Smart direct login | POST | /api/smart/directLogin |
Confirm exact URLs in browser Network tab if your reverse-proxy path differs.
Menu names vary by BIG-IP / ASM / Advanced WAF version. Use the closest equivalent.
pnsps.gld.gov.hk (or the VS that terminates TLS for the site).accessToken became "undefined"/api/login/api/refresh-token/api/smart/login / /api/smart/directLogin if using iAM SmartThat violation name is what you exception.
/api/login/api/refresh-token/api/smart/login/api/smart/directLoginIn the policy, review anything that inspects or rewrites responses:
/api/*, or exclude the URLs above.-, _, . and long base64url strings.From the blocked request in the event log:
/api/login and/or /api/refresh-token (and smart login URLs if needed)If the log shows a bot challenge or CAPTCHA HTML page on login/refresh:
/api/login/api/refresh-tokenapplication/json from the app, not an HTML interstitial.Content-Type: application/jsonaccessToken and refreshToken strings (three JWT segments each)localStorage.getItem('accessToken')
Must never be the literal "undefined".
PNSPS SPA needs
/api/loginand/api/refresh-token(POST, JSON), and if used/api/smart/loginand/api/smart/directLogin, to return the backend body unchanged in WAF blocking mode. The WAF must not replace them with an HTML block/challenge page or strip/alteraccessToken. Please identify the violating signature/URL from ASM Event Logs and add a narrow exception; also disable response Data Guard / bot challenge on those API paths if they rewrite JSON.
| Test | Expected |
|---|---|
| Normal password login + logout | Dashboard OK; clean logout |
Console: plant accessToken = eyJhbGciOiJIUzUxMiJ9.Pj4-.sig without userData, reload, wait 15s |
No repeating InvalidCharacterError; redirect to /login |
Console: plant accessToken = "undefined" with userData, reload |
Within ~10s redirect to /login; session keys cleared |
Login/refresh body missing accessToken (WAF case) |
Stay on login / fail page or force logout — not permanent white screen |
| iAM Smart success | Still works with real JWT |
Plant base64url payload that old atob rejected:
localStorage.removeItem('userData');
localStorage.setItem('accessToken', 'eyJhbGciOiJIUzUxMiJ9.Pj4-.sig');
location.reload();
Plant stuck "undefined" session:
localStorage.setItem('userData', JSON.stringify({id:1,type:'IND',role:'primary'}));
localStorage.setItem('accessToken', 'undefined');
location.reload();
Cleanup:
localStorage.removeItem('accessToken');
localStorage.removeItem('userData');
location.reload();
| Layer | Role |
|---|---|
| Frontend | Do not store bad tokens; force logout instead of stuck white screen |
| F5 WAF / LB | Do not damage login/refresh JSON so accessToken is present and valid |
src/components/RefreshTokenProvider.js — base64url decode + force logout on bad tokensrc/auth/index.js — isAccessTokenUsable, forceLocalLogoutRedirect, login/refresh guardssrc/auth/jwt/jwtService.js — same guard on JwtService 401 refresh