I have a Spring REST application which at first was secured with Basic authentication.
Then I added a login controller that creates a JWT JSON Web Token which is used in subsequent requests.
Could I move the following code out of the login controller and into the security filter? Then I would not need the login controller any longer.
tokenAuthenticationService.addTokenToResponseHeader(responseHeaders, credentialsResource.getEmail());
Or could I remove the Basic authentication?
Is it a good design to mix Basic authentication with a JWT?
Although it all works fine, I'm a bit in the dark here as to best design this security.
Basic authentication is an HTTP-based authentication approach and is the simplest way to secure REST APIs. It uses a Base64 format to encode usernames and passwords, both of which are stored in the HTTP header.
Bottom line. Although JWT does eliminate the database lookup, it introduces security issues and other complexities while doing so. Security is binary—either it's secure or it's not. Thus making it dangerous to use JWT for user sessions.
OAuth 2.0 is the best choice for identifying personal user accounts and granting proper permissions. In this method, the user logs into a system. That system will then request authentication, usually in the form of a token.
If the requested resource is protected, Spring Security will use our custom Filter to validate the JWT token, and build an Authentication object and set it in Spring Security specific SecurityContextHolder to complete the authentication progress. If the JWT token is valid it will return the requested resource to client.
JSON Web Token (JWT) is a good choice for protecting a REST API - the following article will show the minimal steps to setup a Spring Boot application with JWT. The Bootify Builder can generate you a runnable Spring Boot application - with your custom database schema, REST API and Spring Security with JWT.
:) If the JWT represents a verified identity, yes, I'd consider TLS mandatory, otherwise its (much) easier for MITM attacks. Last background question before I attempt to answer: is your REST client a JavaScript (JQuery, Angular, etc) or mobile client? Good point. I reckon there's no need for basic authentication in a jwt setup..
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.
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.
The idea is that the end user is authenticated via one endpoint, e.g. /login/token
using whatever mechanism you want, and the response should contain the JWT that is to be sent back on all subsequent requests. The JWT should be a JWS (i.e. a cryptographically signed JWT) with a proper JWT expiration (exp
) field: this ensures that the client cannot manipulate the JWT or make it live longer than it should.
You don't need an X-Auth-Token
header either: the HTTP Authentication Bearer
scheme was created for this exact use case: basically any bit of information that trails the Bearer
scheme name is 'bearer' information that should be validated. 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:
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.
Then, on every request into your server, ensure that your own JavaScript code reads the cookie value and sets this in a custom header, e.g. X-CSRF-Token and verify that value on every request in the server. External domain clients cannot set custom headers for requests to your domain unless the external client gets authorization via an HTTP Options request, so any attempt at a CSRF attack (e.g. in an IFrame, whatever) will fail for them.
This is the best of breed security available for untrusted JavaScript clients on the web today that we know of. Stormpath wrote an article on these techniques as well if you're curious. HTH!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With