The auth token stays in the cookie
Login, register, logout, and the current user live under /api. The token is httpOnly auth_token. It never lands in localStorage or in the JSON body.
The public API for auth is four routes: /api/login, /api/register, /api/logout, and /api/user. Sanctum writes the session into an httpOnly cookie named auth_token. Login no longer returns a token field. Nothing on the client writes a token to localStorage.
If a script on the origin can read the session, XSS can send it away. An httpOnly cookie is not reachable from JavaScript. The same injection cannot copy auth_token. Logout deletes the server token and the cookie, so a copied cookie stops working immediately.
CSRF on every write
Unsafe methods need the CSRF cookie and the matching header. The frontend fetches the cookie once, then sends the header on every write. A missing or stale header returns 419, not a validation error that looks like a bad password.
Admin routes sit behind the same cookie session. An expired session redirects to login instead of a broken page. The login route rotates the session id.
What the tests lock
Four cases used to regress. No token in the login JSON. The httpOnly flag present on auth_token. A write rejected without the CSRF header. /api/user returns 401 after logout.
The rule is short enough to keep. Tokens live in cookies. JSON bodies carry user fields, not secrets. If a new screen needs the current user, it calls /api/user with credentials included. It does not invent a second store.
