Description
Summary
It would be nice to have a builder that enables authentication for web API with JWT. I know that ResourceServer and AuthorizationServer exist but they require a clear understanding of oauth and related concepts. Even if it is just a few lines of code, the point is not only to have something that works but also to understand the underlying mechanisms.
For the time being we have two choices : oauth and ResourceServer and AuthorizationServer or custom filters boilerplate.
Issue #368 is now closed but I think this feature should be considered so stateless api authentication would be at par with website authentication (formlogin()
, etc...)
Actual Behavior
Authentication based on user password and jwt token (provided to the client after a successful username/password authentication) requires custom filter implementations.
One filter intercept POST on /authentication (for example) and returns a a JWT authorization token or HTTP 401.
One filter intercept all requests and rebuild a SecurityContext
based on Authorization header.
Just a few elements are specific : authentication path (/authentication in my example), secret, algorithm, username property, password property, expiration, custom claims (other than authorities).
The configure method looks like that :
http
.csrf().disable()
.cors()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
.addFilter(new MyUsernamePasswordAuthenticationFilter(authenticationManager()))
.addFilterAfter(new MyJwtTokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
Expected Behavior
Default implementations of these two filters could be provided out of the box, like for formLogin()
or cors()
.
Default settings could apply for path, username property, password property and the builder would just ask for the secret and the algorithm. About the claims, a common use case is to store the authorities in a property named 'authorities'.
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
could also be applied automatically.
If these 2 filters are added in the framework, they should be enabled independently, for instance we may want to keep the control on username & password authentication with a custom filter or @PostMapping
endpoint.
It could look like this
http.enableJwt("mysecret", SignatureAlgorithm.HS512)
.withUsernamePasswordAuthentication()
.withAuthorizationHeaderAuthentication();
default settings :
- path for authentication is
/authentication
- request body for authentication is
{"username":"...", "password:".."}
- name of the header is Authorization, its value has a prefix named Bearer
- issuedAt : now
Additional methods on the builders would allow to redefine these settings.
The builder could also provide a method that accepts a Function<Authentication, String>
so the developer can keep full control on the token creation.