In most cases, REST APIs should be accessed only by authorized parties. Spring framework provides many ways to configure authentication and authorization for an application. Another good thing is that the framework usually provides relatively good default settings. But nevertheless, it may be better to understand what’s going on rather then rely on the defaults.
This post contains a list of things which may be good to pay attention to when you configure or review authentication and authorization settings for a RESTful application based on Spring (boot) framework. However this is not a comprehensive guideline (if such a guideline even exist) which tells how to configure authentication and authorization for an application based on Spring framework. It’s more like a collection of tips and suggestions. Furthermore, any other suggestions and comments are more than welcome.
Consider using OAuth2 or JWT
Usually only authorized users or applications should be able to access a RESTful service. A RESTful web application doesn’t normally use HTTP sessions. Instead, it performs access checks for each incoming request.
One of the ways to restrict access to a RESTful application is to start using API keys. But OAuth2 or JWT (JSON Web tokens) may sound like a better option. OAuth2 and JWT are frameworks for authentication and authorization which are described in RFCs. The frameworks allow configuring and controlling authentication and authorization processes in a more flexible way than API keys do. But the cost for that is an additional infrastructure and complexity. Fortunately, there are already implementations of these standards, and even services which provide all required infrastructure (for example, application load balancers in AWS support OAuth2).
Even if an application uses OAuth2 or JWT, we need to make sure that it uses it correctly, for example:
- the application validates tokens and access rights for each request
- the application doesn’t expose access tokens (for example, no tokens should be put to logs)
- access tokens have a correct lifetime
- and so on
This advice can be found in every guideline/article/book/presentation about securing a web application. Using TLS is important especially if an application uses OAuth2 (or API keys) for authentication since the protocol explicitly relies on TLS for providing confidentiality and integrity.
In Spring, you can use
requiresSecure() method. Don’t forget to enable HSTS header. Here is an example:
An application may support only plain HTTP and stay behind a reverse proxy which provides TLS. In this case, make sure that the reverse proxy is configured to use HTTPS and HSTS header. The proxy should deny plain HTTP connections, or always redirect to HTTPS.
Configure session management
Spring framework provides a mechanism to establish an HTTP session. If a RESTful service authenticates each request (which mostly is the case), then it doesn’t need any session management mechanism. In this case, it may be better to instruct Spring framework not to create any session:
Disable login and logout pages
Spring framework provides a login form and a logout page out of the box. This may be useful for a web application with a GUI, but most probably a RESTful application doesn’t need these pages. This is the case for sure if the application uses OAuth2, JWT or API tokens for access control. Then, it might make sense to disable these features for the application:
Disable Basic HTTP authentication
Most probably a RESTful application doesn’t need HTTP Basic authentication, so it may be better to disable it:
Disable anonymous access
If a RESTful service should be accessed only by authorized clients, then it may be better to disable anonymous access:
Authorizing requests by HTTP methods may lead to a problem
antMatchers() method allows to specify an HTTP method for which you’d like to configure access. It may look like the following:
Depending on the rest of the security configuration, it may result to a problem because we missed HEAD method in the configuration above. To avoid such issues, it may be better to specify API endpoints in
antMatchers(), require all requests to be authenticated, and call
denyAll() in the end.
fullyAuthenticated() methods may be used to require all requests to be authenticated. The difference is that the last one doesn’t take into account remember-me feature. By the way, most likely a RESTful service doesn’t need remember-me. Here is what security config may look like:
Disable creating a default user with random password
By default, Spring framework creates a default user
user with a random password. Then, the framework prints out the password to logs. It looks like the following:
Using default security password: 94251362-f9cc-4c01-95be-121e5b6e1865
Most probably an application doesn’t need this used in production especially if it uses OAuth2 or JWT. So, it may be better to disable it even if it doesn’t hurt. Overriding
authenticationManagerBean() method in security configuration helps although this solution may look a bit strange (you can find a bit more details here):