Spring Security with JWT

Jakub Leško on January 14, 2019

This post were originally posted on my blog. Spring Security’s default behavior is easy to use for a standard web application. It uses cookie-base... [Read Full]
markdown guide
 

Great Article! Good job!

A quick question: Why here are you checking the header and not the authentication object?

I mean, you already checked the header in getAuthentication()

        var authentication = getAuthentication(request);
        var header = request.getHeader(SecurityConstants.TOKEN_HEADER);

        if (StringUtils.isEmpty(header) || !header.startsWith(SecurityConstants.TOKEN_PREFIX)) {
            filterChain.doFilter(request, response);
            return;
        }

Like this, should also work, or not? :D

        var authentication = getAuthentication(request);

        if (authentication == null) {
            filterChain.doFilter(request, response);
            return;
        }

Again, great article!

 

Well, you're right. My bad 😀
I'll update the code. Thanks for your attention 🙂

 

For starters, great introduction to JWT security! But i was looking around to see if i could authenticate users with a database instead of the in memory database that is used by default. Do you happen to have an example for this?

EDIT:
Few minutes after i asked the question i stumbled upon the answer...

for those interested i changed this:

auth.inMemoryAuthentication()
        .withUser("user")
        .password(passwordEncoder().encode("password"))
        .authorities("ROLE_USER");

to this

auth.userDetailsService(customUserDetailsService)
        .passwordEncoder(passwordEncoder());

password encoder is just a constructor for a BcryptEncoder, and the userdetail service provides a method to load by username from the repository, and get authorities.

 

This is a great explanation! I have been trying to get this to work for weeks and now I get it!

 

Thank you! I'm writing another article about token refreshing so stay tuned :)

 

But i'm curious to know how to use UserDetails ?here ?

 

Hello ! Im waiting for your article about implementing token refreshing.Any plans to do in the future ?

Hello Kivimango. I'm sorry that it takes so long but I have too much work to do so the article is still a draft. But I promise I'll try to complete the article asap.

I already started with code updates in a separate branch, so you can check the progress there

 

Awesome! Another thing that I have been trying to understand is how to extend what you have to a user repository.

 

I have like 3 weeks looking for a clear explanation of the basic jwt integration with spring security..

Great Job!

 

Hi . Could you please explain where you got the JWT Token From?
When doing the operation below

GET http://localhost:8080/api/private
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJzZWN1cmUtYXBpIiwiYXVkIjoic2VjdXJlLWFwcCIsInN1YiI6InVzZXIiLCJleHAiOjE1NDgyNDI1ODksInJvbCI6WyJST0xFX1VTRVIiXX0.GzUPUWStRofrWI9Ctfv2h-XofGZwcOog9swtuqg1vSkA8kDWLcY3InVgmct7rq4ZU3lxI6CGupNgSazypHoFOA
 

Hi. You can find JWT in HTTP header Authorization in response from /api/authenticate.

 

Thank for the tutorial. But I don't really agree with your coding style, should be more careful thought. Like the code below, the authentication object should not get from the first place.

    @Override
    protected void doFilterInternal(...) throws ... 
    {
        var authentication = getAuthentication(request);
        var header = request.getHeader(SecurityConstants.TOKEN_HEADER);
        if (StringUtils.isEmpty(header)...
           return...
 

hmmm could you tell me how to this implementation use refresh_token? for example storage this refresh in database. And when token is expired check the refresh_token?
I have similar implementation in my project but I want to extend with refresh_token.

 
 
 

Thank you for the tutorial. I was wondering how can i implement the @PreAuthorize annotation and the whole roles thing in my spring security(I've looked into other tutorials but it didn't help). Thank you for your time.

 

In JwtAuthenticationFilter, method attemptAuthentication, the authentication data (username and password) are got from request URL. I need that the username and password got from request body (example JSON: { "username": "john", "password":"mysecret" }). How can I made this?

 

It's very simple. You just need to update JwtAuthenticationFilter class to parse received JSON data.

Example:

// POJO with your login data
public class LoginData {
    private String username;
    private String password;
    /* getters, setters */
}
// JwtAuthenticationFilter.java
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
    var loginData = parseLoginData(request);
    var authenticationToken = new UsernamePasswordAuthenticationToken(loginData.getUsername(), loginData.getPassword());

    return authenticationManager.authenticate(authenticationToken);
}

private LoginData parseLoginData(HttpServletRequest request) {
    try {
        ObjectMapper mapper = new ObjectMapper();
        return mapper.readValue(request.getInputStream(), LoginData.class);
    } catch (IOException exception) {
        // Return empty "invalid" login data
        return new LoginData();
    }
}
 

I still see set-cookie in response. And each time request /api/private, it will create a new JSESSIONID


set-cookie: JSESSIONID=...; Path=/; HttpOnly

 

It should not create JSESSIONID cookie. Do you have a git repository with your code? We can check it together :)

 

Great article, clean and straightforward. Awesome!

 

Hi Could you please explain where you get the JWT Token from ? the one that you use for calling the API End Point .

 

But sending the username and password in url localhost:8080/api/authenticate?us... , isn't it a security flaw itself?

 

For example purposes it's fine. Also, if you're using HTTPS then no one will see query params.

You can send username and password as standard POST data with content-type application/x-www-form-urlencoded and then those params will not be part of the URL.

 
 
 

It's valid syntax since Java 10. I also think that var is more elegant than full type declaration (it doesn't mean that Java is now dynamically typed).

 

Great Article! it works fine on Postman everything succeeds but it keeps throwing 403 error on Angular 8 any fixes I can apply?

 

Super Good. Was struggling to understand this for a week :)

 
code of conduct - report abuse