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 that you try this configuration and tweak it to find a good compromise between security and usability.

I used a global file that holds all my security-relevant variables. This approach makes it easier to update the security-relevant values later on:

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. However, I recommend creating this file as it’ll make changing values, like the time-to-live, so much easier.

Next, create a class in which you define what type of authentication to use and which resources 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. Leaving this resource open allows users to log in and acquire a token.

The very last line applies the 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 the previously created user class so that Spring boot and Hibernate can use it for both the RESTful API implementation and Spring Security.

Let’s start by modifying the UserService class 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;
    }
}

Note that the overridden method 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 existing User class implement the UserDetails interface:

@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 them, so all the respective functions return true. An additional function returns a list of roles for each user. This allows the security system to distinguish between regular users and administrators.

The UserAuthority is a straight-forward 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 tweak the behavior 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 )

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.