First of all, I assume a backend that control inputs to prevent XSS vulnerabilities.
In this answer @Les Hazlewood explain how to protect the JWT in the client side.
Assuming 100% TLS for all communication - both during and at all times after login - authenticating with username/password via basic authentication and receiving a JWT in exchange is a valid use case. This is almost exactly how one of OAuth 2's flows ('password grant') works. [...]
You just set the Authorization header:
Authorization: Bearer <JWT value here>
But, that being said, if your REST client is 'untrusted' (e.g. JavaScript-enabled browser), I wouldn't even do that: any value in the HTTP response that is accessible via JavaScript - basically any header value or response body value - could be sniffed and intercepted via MITM XSS attacks.
It's better to store the JWT value in a secure-only, http-only cookie (cookie config: setSecure(true), setHttpOnly(true)). This guarantees that the browser will:
- only ever transmit the cookie over a TLS connection and,
- never make the cookie value available to JavaScript code.
This approach is almost everything you need to do for best-practices security. The last thing is to ensure that you have CSRF protection on every HTTP request to ensure that external domains initiating requests to your site cannot function.
The easiest way to do this is to set a secure only (but NOT http only) cookie with a random value, e.g. a UUID.
I don't understand why we need the cookie with the random value to ensure that external domains initiating requests to your site cannot function. This doesn't come free with Same-origin policy?
From OWASP:
Checking The Origin Header
The Origin HTTP Header standard was introduced as a method of defending against CSRF and other Cross-Domain attacks. Unlike the referer, the origin will be present in HTTP request that originates from an HTTPS url.
If the origin header is present, then it should be checked for consistency.
I know that the general recommendation from OWASP itself is Synchronizer Token Pattern but I can't see what are the vulnerabilities that remains in:
- TLS + JWT in secure httpOnly cookie + Same-origin policy + No XSS vulnerabilities.
UPDATE 1: The same-origin policy only applies to XMLHTTPRequest, so a evil site can make a form POST request easily an this will break my security. An explicit origin header check is needed. The equation would be:
- TLS + JWT in secure httpOnly cookie + Origin Header check + No XSS vulnerabilities.