0

I'm trying to implement JWT. I have two endpoints: /api/auth/signin for authentication that returns generated JWT token and /api/auth/me that should return user based on JWT token in the header. I'm trying to configure Spring Security to have access to /api** for only authorized users and I need to exclude /api/auth/signin Here is a configure() method from class that extends WebSecurityConfigurerAdapter:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.antMatcher("/api**")
            .httpBasic().disable()
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
                .antMatchers(HttpMethod.POST, "/api/auth/signin").permitAll()
                .anyRequest().authenticated()
            .and()
            .addFilterBefore(jwtAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
}

But it still invokes JwtAuthorizationFilter for /api/auth/signin. I also tried to ignore this endpoint with:

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(HttpMethod.POST,"/api/auth/signin");
}

Is there any other way to ignore it or maybe permitAll() and ignoring() should be used differently?

user2452483
  • 357
  • 1
  • 4
  • 13
  • Are you sure you use POST request when call the /api/auth/signin endpoint? Also, is it possible than the signin endpoint redirects you to an other endpoint? And the filter is called during the redirection? – Selindek Nov 24 '18 at 11:37
  • @Selindek, Yes, POST request is used. But even if I remove HttpMethod.POST it still invokes JwtAuthorizationFilter. And it doesn't redirect to another endpoint. – user2452483 Nov 24 '18 at 11:42
  • Is UsernamePasswordAuthenticationFilter getting involved before JWT filter? – Rahul Vedpathak Nov 24 '18 at 11:47
  • @RahulVedpathak, No, this filter is not getting involved before JWT filter – user2452483 Nov 24 '18 at 11:56
  • I think you should use AuthenticationServerConfiguration and ResourceServerConfiguration instead of configuring the JWT manually. – Selindek Nov 24 '18 at 12:14

2 Answers2

0

You need a AbstractAuthenticationProcessingFilter filter for generating JWT token on /api/auth/signin and a GenericFilterBean for retrieving authentication object and putting it in SecurityContextHolder

there is a good sample in the following link:

https://auth0.com/blog/securing-spring-boot-with-jwts/

http.antMatcher("/api**")
                .httpBasic().disable()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            // We filter the api/login requests
            .addFilterBefore(new JWTLoginFilter("/api/auth/signin", authenticationManager()),
                    UsernamePasswordAuthenticationFilter.class)
            // And filter other requests to check the presence of JWT in header
            .addFilterBefore(new jwtAuthorizationFilter(),
                    UsernamePasswordAuthenticationFilter.class);

And I'm not sure if it is possible to return generated token from successfulAuthentication() in JWTLoginFilter in the response body

the sample returns token in Authorization header of the response. but if you want to return token in the body. you could use the following code:

static void addAuthentication(HttpServletResponse res, String username) {
        String JWT = Jwts.builder()
                .setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
//        res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);
        JSONObject tokenJson = new JSONObject();
        tokenJson.put(SecurityConstants.JWT_TOKEN, JWT);
        tokenJson.put(SecurityConstants.USERNAME, username);
        try(PrintWriter writer = res.getWriter()) {
            writer.print(tokenJson.toJSONString());
            writer.flush();
        } catch (IOException e) {
            LOG.error("error ...");
        }
//        res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);
    }
Mehran Mastcheshmi
  • 785
  • 1
  • 4
  • 12
  • I saw this article, but in my implementation, JWT token generated in RestController, mapped to /api/auth/signin and I need to make Spring Security ignore it. And I'm not sure if it is possible to return generated token from successfulAuthentication() in JWTLoginFilter in the response body. – user2452483 Nov 24 '18 at 15:03
  • if you do not want jwtAuthorizationFilter is not invoked for signing request. you could you a different prefix(such as auth/signin that is not started with "api") https://stackoverflow.com/questions/36795894/how-to-apply-spring-security-filter-only-on-secured-endpoints I also have updated my post to show you how you can send the token in the body – Mehran Mastcheshmi Nov 24 '18 at 15:54
-2

Why not create two types of endpoints:

  1. authorized API's: "/api/auth/**"
  2. unauthorized API's: "/api/noauth/**"

And then configure security only for "/api/auth/**"

Ravi Sharma
  • 197
  • 1
  • 4
  • It will not work for the case when resources are available without authentication and only editing requires credentials. – wpater Feb 03 '21 at 08:29