How to implement JWT authentication in Spring Security and Angular – Part 2

In this part of the series we’ll make sure that Spring Security restricts access to certain resources and uses our custom bearer token authorization method to allow authenticated users to access resources.

Configuring Spring Security

When you try to access any resource of the REST endpoint right now, you’ll see this dialogue:

Figure 1: Spring’s default security login screen

We don’t want to use this method of authentication. Therefore, we’ll have to configure Spring Security to use JWTs instead. Let’s start with the allowed methods, headers, and origins:

@Configuration
public class RestConfig
{
    @Bean
    public CorsFilter corsFilter()
    {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();

        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("DELETE");
        source.registerCorsConfiguration("/**", config);

        return new CorsFilter(source);
    }
}

This very simple config will allow five methods, all headers, and all origins. It’s an extremely unrestrictive config and I only recommend it for development and testing purposes. It will make it easy to send requests to the server but it opens doors for potential attackers.

This is a config, that a lot of other tutorials didn’t include and that gave me a hard time figuring out what’s wrong. If you’re having troubles with CORS errors between Angular and Spring, make sure to try the config and tweak it to find a good compromise between security and usability.

To make changing certain values easier, I used a global file that holds all my security relevant variables:

public final class SecurityGlobals
{
    public static final String HEADER_FIELD_NAME = "Authorization";
    public static final String TOKEN_PREFIX = "Bearer ";
    public static final String ROLE_PREFIX = "";
    public static final String ISSUER = "JWT_EXAMPLE_APP";
    public static final Long TIME_TO_LIVE = 300000L; // 5 minutes
    public static final SecretKey SIGNING_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);
}

It’s entirely optional, but I recommend it, because it’ll make changing values, like the time-to-live, so much easier.

Next, create a class in which we define what type of authentication to use and what resources we want to secure:

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
    // Variables, Constructor

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        http
            .cors().and()
            .httpBasic().disable()
            .csrf().disable()
            .headers().frameOptions().disable()
            .and().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and().authorizeRequests()
            .antMatchers(HttpMethod.POST, "/authentication/").permitAll()
            .antMatchers(HttpMethod.POST, "/users/").permitAll()
            .antMatchers("/h2-console/*").permitAll()
            .anyRequest().authenticated()
            .and().apply(new AuthenticationTokenConfigurer(authenticationTokenProvider));
    }

The first half of the configure method turns off certain security features. Again, this is a very unrestrictive policy and it should only be used to get Spring Security up and running.

The second half configures a few resources I didn’t want to secure. For example, the /authentication/ resource. This will allow users to login and acquire a token.

The very last line applies our custom JWT authentication mechanism, which we still have to implement.

Changing the user entity

But before we can implement the JWT features, we’ll have to change our previously created user so that we can use it for both, our own implementation, and Spring Security.

Let’s start by modifying the UserService class, we created eralier, so that it implements Spring Security’s UserDetailsService interface:

@Service
public class UserService implements IUserService, UserDetailsService
{
    private final IUserDao userDao;

    // The methods from earlier

    @Override
    public UserDetails loadUserByUsername(String s)
    {
        User u = null;

        try
        {
            u = userDao.findOneByUsername(s);
        }
        catch (Exception e)
        {
            // Proper exception handling omitted
        }

        return u;
    }
}

The overriden method, however, returns a UserDetails object. Therefore we’ll either need to create a new custom user details class (which is redundant) or we’ll have to make our User implement UserDetails:

@Entity
public class User implements UserDetails
{
    // Everything else from before

    @Override
    public boolean isAccountNonExpired()
    {
        return true;
    }

    @Override
    public boolean isAccountNonLocked()
    {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired()
    {
        return true;
    }

    @Override
    public boolean isEnabled()
    {
        return true;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities()
    {
        List<GrantedAuthority> roles = new ArrayList<>();

        roles.add(new UserAuthority(this.isAdmin == null ? false : this.isAdmin));

        return roles;
    }
}

Implementing this method will add a few new fields to our User to check whether the account is valid, activated, etc. As you can see, I won’t use these, so all the respective functions return true. An additional function returns a list of roles a user has. This enables the security system to distinguish regular user from, for example, administrators.

The UserAuthority is a very simple class that implements the GrantedAuthority interface and returns a string:

public class UserAuthority implements GrantedAuthority
{
    private boolean admin;

    public UserAuthority(boolean admin)
    {
        this.admin = admin;
    }

    @Override
    public String getAuthority()
    {
        return SecurityGlobals.ROLE_PREFIX + (admin ? "ADMINISTRATOR" : "USER");
    }
}

You can always change the behaviour of these classes to fit your needs.

These steps will configure Spring Security not to use the built-in login form, we saw earlier. Instead, it’ll use our custom JWT Configurer, Filter, and Provider, which we still have to implement. All that’s going to happen in the next part of this series.

Table of contents

Part 1 – Basics of JWT and the project scaffolding
Part 2 – Configure Spring Security (You are here)
Part 3 – JWT token generation, validation, and user authentication
Part 4 – JWT authentication in an Angular frontend
Part 5 – Token renewal

6 thoughts on “How to implement JWT authentication in Spring Security and Angular – Part 2

    1. Hi! That shouldn’t have happened – sorry! The links in the table of contents got updated too early and the third part of the series will be available in about an hour from now. The other parts will follow in a few days.

      Liked by 1 person

Leave your two cents, comment here!

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.