選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

7.6 KiB

F5 BIG-IP WAF — Login / Refresh accessToken follow-up

Date: 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.

Goal

/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:

  • Replace the body with an HTML block / challenge page
  • Strip or alter the accessToken field
  • Rewrite long base64url JWT strings in JSON

App-side mitigation (already done)

Frontend changes stop a permanent stuck white screen:

  • JWT payload decode uses base64url (not raw atob on - / _)
  • Do not store a missing / "undefined" access token
  • Force clear session and redirect to /login when token is unusable

App mitigation does not make a WAF-damaged response succeed. WAF/LB still needs tuning so login/refresh return a real JWT.

API paths to protect (PNSPS)

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.


F5 BIG-IP WAF — step by step

Menu names vary by BIG-IP / ASM / Advanced WAF version. Use the closest equivalent.

1. Confirm which policy sits in front of PNSPS

  1. Log in to the BIG-IP UI.
  2. Go to Local Traffic → Virtual Servers.
  3. Open the virtual server for pnsps.gld.gov.hk (or the VS that terminates TLS for the site).
  4. Note the attached Application Security Policy (ASM) / security policy name.
  5. Also check whether Bot Defense, DoS, or other profiles are attached — those can inject HTML challenges.

2. Find what was blocked when accessToken became "undefined"

  1. Go to Security → Event Logs → Application → Requests
    (or Security → Application Security → Event Logs).
  2. Filter around the time of a failed login or blank dashboard.
  3. Look for:
    • /api/login
    • /api/refresh-token
    • /api/smart/login / /api/smart/directLogin if using iAM Smart
  4. Open the event and record:
    • Support ID
    • Violation name (signature, illegal meta character, evasion, bot challenge, etc.)
    • Whether the response was a block / challenge page instead of JSON

That violation name is what you exception.

3. Ensure API URLs exist in the policy

  1. Open the security policy → URLs (or Policy → URLs).
  2. Ensure these URLs exist (exact path as in Network tab), for example:
    • /api/login
    • /api/refresh-token
    • /api/smart/login
    • /api/smart/directLogin
  3. Method: POST. Prefer a JSON content profile if the policy uses content profiles.

4. Disable response rewriting for these APIs

In the policy, review anything that inspects or rewrites responses:

  1. Data Guard / Response scrubbing / Information leakage
    • Disable for /api/*, or exclude the URLs above.
  2. Response signatures / checks that modify the body
    • Prefer alarm-only on responses for API URLs, or exclude them.
  3. Custom / attack signatures that false-positive on JWT-looking JSON values
    • JWTs contain -, _, . and long base64url strings.
    • From the event log (step 2), Learn / Allow / Exception that signature for that URL only.

5. Add a targeted exception (preferred once violation is known)

From the blocked request in the event log:

  1. Open the request → Accept / Learn or Create exception.
  2. Scope narrowly:
    • URL = /api/login and/or /api/refresh-token (and smart login URLs if needed)
    • Prefer this signature + this URL, not disabling the whole policy
  3. Apply / publish the policy.

6. Bot Defense / challenge pages

If the log shows a bot challenge or CAPTCHA HTML page on login/refresh:

  1. Open Security → Bot Defense (or the policy Bot profile).
  2. Whitelist / exception:
    • /api/login
    • /api/refresh-token
    • smart login paths if needed
  3. Those endpoints must return application/json from the app, not an HTML interstitial.

7. Transparent vs Blocking (UAT validation only)

  1. On a UAT policy clone, briefly use Transparent (or transparent blocking).
  2. Reproduce login / stay on dashboard through refresh.
  3. If the problem disappears only in transparent mode, the blocking policy is still rewriting or blocking — use event logs to exception those violations, then return to Blocking.
  4. Do not leave production in transparent as the long-term fix.

8. Verify end-to-end

  1. Browser → log in → Network → login response:
    • Content-Type: application/json
    • Body contains long accessToken and refreshToken strings (three JWT segments each)
  2. Wait for refresh near expiry (or trigger refresh) → same checks on refresh-token.
  3. Console:
localStorage.getItem('accessToken')

Must never be the literal "undefined".


Message for the F5 admin (copy/paste)

PNSPS SPA needs /api/login and /api/refresh-token (POST, JSON), and if used /api/smart/login and /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/alter accessToken. 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.


App verification checklist (after frontend deploy)

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

Console helpers

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();

Responsibility split

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 token
  • src/auth/index.js — isAccessTokenUsable, forceLocalLogoutRedirect, login/refresh guards
  • src/auth/jwt/jwtService.js — same guard on JwtService 401 refresh
  • Login forms / iAM Smart callbacks — skip success navigate when token unusable