Authentication (Client-side)¶
Stack¶
@nuxtjs/auth ^4.9.1 with the local strategy only. No OAuth, no SSO.
auth: {
strategies: {
local: {
endpoints: {
login: { url: 'webauthenticate', method: 'post', propertyName: 'data' },
user: { url: 'me', method: 'get', propertyName: 'data' },
logout: false
}
}
}
}
Token storage¶
@nuxtjs/auth's default for the local strategy is localStorage (and a cookie for cross-tab). Verify by inspecting the actual storage in a logged-in browser session.
For the user record, there's also an explicit cookie: userdetail (set by the login flow; read by middleware/guest.js):
// middleware/guest.js
var cookie = store.$cookies.get("userdetail");
if (cookie) {
store.$auth.setUser(cookie);
}
So the user record is in a cookie (not httpOnly — both the FE and an XSS attacker can read it).
Login flow¶
- User submits login form on
pages/login.vue $auth.loginWith('local', { data: { email, password } })POSTs to${baseURL}/webauthenticate- On success,
@nuxtjs/authreads the response'sdata.tokenand stores it $auth.useris populated from thedatafield (perpropertyName: 'data')- The
userdetailcookie is set somewhere in the login flow (probably in the page's.then(...)handler) - Redirect to
/dashboard
/me bootstrap¶
On every page load, @nuxtjs/auth calls GET /me to refresh the user record. The response's data field is set as $auth.user.
This means a stale token will fail at /me, and the FE should redirect to login. Verify this redirect actually happens.
Logout¶
logout: false in the strategy means @nuxtjs/auth does not call any logout endpoint. To log out, the FE must:
$auth.logout()— clears local state- Manually clear cookies (
$cookies.removeAll()or per-cookie) - Redirect to
/login
This is purely client-side. The token is not added to a revocation set server-side. A stolen token remains valid until it expires (which, per the BE patterns, is "never explicitly").
Token expiry¶
Probably none. The designer-api's /webauthenticate handler doesn't appear to encode an exp field. Verify by reading the BE handler.
Multi-tab synchronisation¶
Cookies cross tabs, so a login in one tab makes the user "logged in" in another tab on the next page load. But logout in one tab does not auto-logout other tabs — the userdetail cookie clear is per-tab.
To sync: add a window.addEventListener('storage', ...) handler.
CSRF¶
Auth is via header (Bearer token or similar), not cookie. CSRF therefore not exploitable on authenticated endpoints. (The session-cookie issue would apply only if BE handlers ever read req.session.)
Findings¶
F-1: Token has no expiry (MEDIUM)¶
A token issued at any point remains valid forever. Combined with no server-side revocation, a leaked token is a long-lived credential.
Fix: BE-side, encode exp in the token. FE-side, refresh / re-login on expiry.
F-2: No server-side logout (MEDIUM)¶
Logout is purely client-side. Tokens stay valid.
Fix: add a POST /logout endpoint to designer-api; have FE call it before clearing local state.
F-3: userdetail cookie is XSS-readable (LOW)¶
Storing the user record in a non-httpOnly cookie means XSS can read user info (PII).
Fix: keep only the auth token in storage; let the FE fetch /me fresh each session.
F-4: No auth middleware applied globally (HIGH if true — VERIFY)¶
nuxt.config.js's router.middleware: 'axios' runs the axios interceptor, but no auth middleware is in the global chain. Pages don't appear to declare middleware: 'auth' in spot-checks. This means unauthenticated visitors may reach protected pages without redirect.
Verify: try visiting /dashboard without a token; does the FE redirect?
If not, add middleware: 'auth' per-page or set router.middleware: ['auth', 'axios'] globally.
F-5: Role-typed UI gating is enforcement-by-hope (MEDIUM)¶
The Navbar hides nav items based on role_type, but a knowledgeable user can navigate directly via URL (e.g., visit /topics even if the nav item isn't shown). The BE is the only enforcement layer; if BE handlers don't check role_type, the role gating is cosmetic.
Verify: are BE handlers consistent about checking role_type?
Recommendations¶
| ID | Recommendation | Effort |
|---|---|---|
| AC-1 | Verify auth-redirect on unauthenticated visit; add middleware: 'auth' globally if missing |
Small |
| AC-2 | Encode exp in token (BE) + FE refresh-on-expiry |
Medium (BE+FE) |
| AC-3 | Add POST /logout on BE; FE calls it before clearing state |
Small |
| AC-4 | Remove userdetail cookie; rely on /me fetch |
Small |
| AC-5 | Add multi-tab storage listener for logout sync | Small |
| AC-6 | Centralise role IDs as const ROLE = {...} (also referenced from admin_console_R) |
Small |
| AC-7 | Audit BE handlers for consistent role_type checks |
Medium |