0

I am trying to build Websecurity filter, which will authorize any calls to microservices.

Pom.xml

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>       
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
        </dependency>
<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>11</source>
                <target>11</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                        <version>1.18.22</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>
       

WebSecurityConfig

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        // securedEnabled = true,
        // jsr250Enabled = true,
        prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserDetailsServiceImpl userDetailsService;

    @Autowired
    private AuthEntryPointJwt unauthorizedHandler;

    @Bean
    public AuthTokenFilter authenticationJwtTokenFilter() {
        return new AuthTokenFilter();
    }

    @Override
    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().authorizeRequests().antMatchers("/api/v1/auth/**").permitAll().anyRequest()
                .authenticated().and().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }

AuthEntryPointJwt

@Component
public class AuthEntryPointJwt implements AuthenticationEntryPoint {

  private static final Logger logger = LoggerFactory.getLogger(AuthEntryPointJwt.class);

  @Override
  public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
      throws IOException, ServletException {
    logger.error("Unauthorized error: {}", authException.getMessage());

    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

    final Map<String, Object> body = new HashMap<>();
    body.put("status", HttpServletResponse.SC_UNAUTHORIZED);
    body.put("error", "Unauthorized");
    body.put("message", authException.getMessage());
    body.put("path", request.getServletPath());

    final ObjectMapper mapper = new ObjectMapper();
    mapper.writeValue(response.getOutputStream(), body);
  }

}

public class AuthTokenFilter extends OncePerRequestFilter {
  @Autowired
  private JwtUtils jwtUtils;

  @Autowired
  private UserDetailsServiceImpl userDetailsService;

  private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class);

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {
    try {
      String jwt = parseJwt(request);
      if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
        String username = jwtUtils.getUserNameFromJwtToken(jwt);

        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, username,
            userDetails.getAuthorities());
        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

        SecurityContextHolder.getContext().setAuthentication(authentication);
      }
    } catch (Exception e) {
      logger.error("Cannot set user authentication: {}", e.getMessage());
    }

    filterChain.doFilter(request, response);
  }

  private String parseJwt(HttpServletRequest request) {
    String headerAuth = request.getHeader("Authorization");

    if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
      return headerAuth.substring(7, headerAuth.length());
    }

    return null;
  }
}

@Component
public class JwtUtils {
  private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);

  @Value("${app.jwtSecret}")
  private String jwtSecret;

  @Value("${app.jwtExpirationMs}")
  private int jwtExpirationMs;

  public String generateJwtToken(Authentication authentication) {
    return generateTokenFromUsername(String.valueOf(authentication.getPrincipal()));
  }

  public String generateTokenFromUsername(String username) {
    return Jwts.builder().setSubject(username).setIssuedAt(new Date())
        .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs)).signWith(SignatureAlgorithm.HS512, jwtSecret)
        .compact();
  }

  public String getUserNameFromJwtToken(String token) {
    return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject();
  }

  public boolean validateJwtToken(String authToken) {
    try {
      Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
      return true;
    } catch (SignatureException e) {
      logger.error("Invalid JWT signature: {}", e.getMessage());
    } catch (MalformedJwtException e) {
      logger.error("Invalid JWT token: {}", e.getMessage());
    } catch (ExpiredJwtException e) {
      logger.error("JWT token is expired: {}", e.getMessage());
    } catch (UnsupportedJwtException e) {
      logger.error("JWT token is unsupported: {}", e.getMessage());
    } catch (IllegalArgumentException e) {
      logger.error("JWT claims string is empty: {}", e.getMessage());
    }

    return false;
  }

What i am doing here in below is, call another api/endpoint to get the user validated using HttpClient

public class UserDetailsImpl implements UserDetails {
    private static final long serialVersionUID = 1L;

    private Long id;

    private String username;

    private String email;

    @JsonIgnore
    private String password;

    private Collection<? extends GrantedAuthority> authorities;

    public UserDetailsImpl(Long id, String username, String email, String password,
            Collection<? extends GrantedAuthority> authorities) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.password = password;
        this.authorities = authorities;
    }

    public static UserDetailsImpl build(AccessDetailsResponse user) {
        List<GrantedAuthority> authorities = user.getRoleName().stream().map(role -> new SimpleGrantedAuthority(role))
                .collect(Collectors.toList());

        return new UserDetailsImpl(user.getId(), user.getEmail(), user.getEmail(), user.getEmail(), authorities);
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    String validateUserURL = null;

    private Properties myProperties;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        try {
            myProperties = new Properties();
            InputStream input = AuthTokenFilter.class.getClassLoader().getResourceAsStream("config.properties");

            myProperties.load(input);

            String authUrl = myProperties.getProperty("api.auth.url");
            validateUserURL = authUrl + "/api/v1/auth/validateUserAccess";

            AccessDetailsResponse userDetails = validateAccess(validateUserURL, username, "/api/loan/");
            return UserDetailsImpl.build(userDetails);
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 
     * @param uri
     * @param userName
     * @param apiEndPoint
     * @return
     */
    private AccessDetailsResponse validateAccess(String uri, String userName, String apiEndPoint) {
        AccessDetailsResponse accessResponse = null;
        try {
            HttpClient httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_2)
                    .connectTimeout(Duration.ofSeconds(10)).build();

            Map<Object, Object> data = new HashMap();
            data.put("userName", userName);
            data.put("apiName", apiEndPoint);

            HttpRequest request = HttpRequest.newBuilder().POST(ofFormData(data)).uri(URI.create(uri))
                    .header("Content-Type", "application/json").build();

            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
            if (response.statusCode() == 200) {
                Gson jsonObj = new Gson();
                accessResponse = jsonObj.fromJson(response.body(), AccessDetailsResponse.class);
            }

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return accessResponse;
    }

    /**
     * 
     * @param data
     * @return
     */
    private static HttpRequest.BodyPublisher ofFormData(Map<Object, Object> data) {
        var builder = new StringBuilder();
        for (Map.Entry<Object, Object> entry : data.entrySet()) {
            if (builder.length() > 0) {
                builder.append("&");
            }
            builder.append(URLEncoder.encode(entry.getKey().toString(), StandardCharsets.UTF_8));
            builder.append("=");
            builder.append(URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8));
        }
        return HttpRequest.BodyPublishers.ofString(builder.toString());
    }
}

The JAR build from above is included as dependency - pom.xml in all microservices, expecting to get the all apis in microservices getting authorized before access. Also token is generated and sent when the user login, and token will be send in header as 'Bearer ' while making any further calls. But I dont see any logs in validateUserAccess API, getting called. But with dependency added i am getting below response and removing the dependency it is working fine.

timestamp": "2022-02-03T03:50:16.146+00:00",
    "status": 401,
    "error": "Unauthorized",
    "message": "Unauthorized",
    "path": "/api/loan/191"

Update: Above unauthorized message is not from JWTentrypoint class, it is from the microservice where the Custom auth JAR i built is included. I added WebsecurityConfig class in my microservice and permitting all in it, i got response:200.

I referred this https://www.bezkoder.com/spring-boot-jwt-authentication/ and started building it as a standalone jar, then included it as dependency in microservice. But auth jar has been never called.

Whatever I tried so far in https://github.com/patsub/spring-security-jwt

Below is the trace:

[2022-02-27 19:42:59.573[ [3 INFO[ [16696[ [---[ [[on(3)-127.0.0.1][ [36mo.a.c.c.C.[Tomcat].[localhost].[/]      [ [:[ Initializing Spring DispatcherServlet 'dispatcherServlet'
[2022-02-27 19:42:59.574[ [3 INFO[ [16696[ [---[ [[on(3)-127.0.0.1][ [36mo.s.web.servlet.DispatcherServlet       [ [:[ Initializing Servlet 'dispatcherServlet'
[2022-02-27 19:42:59.577[ [3 INFO[ [16696[ [---[ [[on(3)-127.0.0.1][ [36mo.s.web.servlet.DispatcherServlet       [ [:[ Completed initialization in 3 ms
[2022-02-27 19:43:03.385[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@3b2c3f9d, org.springframework.security.web.context.SecurityContextPersistenceFilter@37b33187, org.springframework.security.web.header.HeaderWriterFilter@7a59322f, org.springframework.web.filter.CorsFilter@477318f9, org.springframework.security.web.csrf.CsrfFilter@6c015fbf, org.springframework.security.web.authentication.logout.LogoutFilter@511f5f80, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@4df3000d, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@9aa80ac, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@6750dc5d, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@5f3fe785, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@7c015a23, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1889b178, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@41edbebb, org.springframework.security.web.session.SessionManagementFilter@3552bcee, org.springframework.security.web.access.ExceptionTranslationFilter@d438e1b, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@fdcdbe8]] (1/1)
[2022-02-27 19:43:03.386[ [3DEBUG[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Securing GET /api/valuation/details/id/38
[2022-02-27 19:43:03.387[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking WebAsyncManagerIntegrationFilter (1/16)
[2022-02-27 19:43:03.390[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking SecurityContextPersistenceFilter (2/16)
[2022-02-27 19:43:03.393[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mw.c.HttpSessionSecurityContextRepository[ [:[ Did not find SecurityContext in HttpSession 2C0701A217A4019C38B63040C5632635 using the SPRING_SECURITY_CONTEXT session attribute
[2022-02-27 19:43:03.395[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mw.c.HttpSessionSecurityContextRepository[ [:[ Created SecurityContextImpl [Null authentication]
[2022-02-27 19:43:03.400[ [3DEBUG[ [16696[ [---[ [[nio-8082-exec-1][ [36ms.s.w.c.SecurityContextPersistenceFilter[ [:[ Set SecurityContextHolder to empty SecurityContext
[2022-02-27 19:43:03.400[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking HeaderWriterFilter (3/16)
[2022-02-27 19:43:03.401[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking CorsFilter (4/16)
[2022-02-27 19:43:03.413[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking CsrfFilter (5/16)
[2022-02-27 19:43:03.416[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.csrf.CsrfFilter        [ [:[ Did not protect against CSRF since request did not match CsrfNotRequired [TRACE, HEAD, GET, OPTIONS]
[2022-02-27 19:43:03.416[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking LogoutFilter (6/16)
[2022-02-27 19:43:03.416[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.s.w.a.logout.LogoutFilter           [ [:[ Did not match request to Ant [pattern='/logout', POST]
[2022-02-27 19:43:03.416[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking UsernamePasswordAuthenticationFilter (7/16)
[2022-02-27 19:43:03.416[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mw.a.UsernamePasswordAuthenticationFilter[ [:[ Did not match request to Ant [pattern='/login', POST]
[2022-02-27 19:43:03.416[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking DefaultLoginPageGeneratingFilter (8/16)
[2022-02-27 19:43:03.416[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking DefaultLogoutPageGeneratingFilter (9/16)
[2022-02-27 19:43:03.417[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36m.w.a.u.DefaultLogoutPageGeneratingFilter[ [:[ Did not render default logout page since request did not match [Ant [pattern='/logout', GET]]
[2022-02-27 19:43:03.417[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking BasicAuthenticationFilter (10/16)
[2022-02-27 19:43:03.417[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.s.w.a.www.BasicAuthenticationFilter [ [:[ Did not process authentication request since failed to find username and password in Basic Authorization header
[2022-02-27 19:43:03.417[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking RequestCacheAwareFilter (11/16)
[2022-02-27 19:43:03.418[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.s.w.s.HttpSessionRequestCache       [ [:[ Removing DefaultSavedRequest from session if present
[2022-02-27 19:43:03.418[ [3DEBUG[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.s.w.s.HttpSessionRequestCache       [ [:[ Loaded matching saved request http://localhost:8082/api/valuation/details/id/38
[2022-02-27 19:43:03.420[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking SecurityContextHolderAwareRequestFilter (12/16)
[2022-02-27 19:43:03.423[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking AnonymousAuthenticationFilter (13/16)
[2022-02-27 19:43:03.425[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.s.w.a.AnonymousAuthenticationFilter [ [:[ Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=2C0701A217A4019C38B63040C5632635], Granted Authorities=[ROLE_ANONYMOUS]]
[2022-02-27 19:43:03.426[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking SessionManagementFilter (14/16)
[2022-02-27 19:43:03.426[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking ExceptionTranslationFilter (15/16)
[2022-02-27 19:43:03.426[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.security.web.FilterChainProxy       [ [:[ Invoking FilterSecurityInterceptor (16/16)
[2022-02-27 19:43:03.432[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36medFilterInvocationSecurityMetadataSource[ [:[ Did not match request to org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest$EndpointRequestMatcher@703b28c8 - [permitAll] (1/2)
[2022-02-27 19:43:03.433[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.s.w.a.i.FilterSecurityInterceptor   [ [:[ Did not re-authenticate AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=2C0701A217A4019C38B63040C5632635], Granted Authorities=[ROLE_ANONYMOUS]] before authorizing
[2022-02-27 19:43:03.433[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.s.w.a.i.FilterSecurityInterceptor   [ [:[ Authorizing filter invocation [GET /api/valuation/details/id/38] with attributes [authenticated]
[2022-02-27 19:43:03.440[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.s.w.a.expression.WebExpressionVoter [ [:[ Voted to deny authorization
[2022-02-27 19:43:03.441[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.s.w.a.i.FilterSecurityInterceptor   [ [:[ Failed to authorize filter invocation [GET /api/valuation/details/id/38] with attributes [authenticated] using AffirmativeBased [DecisionVoters=[org.springframework.security.web.access.expression.WebExpressionVoter@2de672fd], AllowIfAllAbstainDecisions=false]
[2022-02-27 19:43:03.456[ [3TRACE[ [16696[ [---[ [[nio-8082-exec-1][ [36mo.s.s.w.a.ExceptionTranslationFilter    [ [:[ Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=2C0701A217A4019C38B63040C5632635], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied

org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:73) ~[spring-security-core-5.5.2.jar:5.5.2]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.attemptAuthorization(AbstractSecurityInterceptor.java:238) ~[spring-security-core-5.5.2.jar:5.5.2]
Pat
  • 535
  • 1
  • 16
  • 41
  • you are most likely suffering from this https://stackoverflow.com/questions/56589896/how-to-autowire-a-component-in-a-dependency-external-jar-in-spring/56590175 but im going to give you some pointers. First of all, spring boot comes with a built in jwtfilter so dont write your own, custom security is bad practice. How to enable the built in jwtfilter https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html#oauth2resourceserver-jwt-sansboot also you dont need to pull in a third party jwt library like jjwt spring already comes with nimbus jwt. – Toerktumlare Feb 03 '22 at 09:36
  • to decode the jwt you just build a jwtdecoder https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html#oauth2resourceserver-jwt-decoder-builder and if you are writing a lib jar that is to be included into other applications you should seriously consider writing a starter https://www.baeldung.com/spring-boot-custom-starter instead of a free standing jar. – Toerktumlare Feb 03 '22 at 09:37
  • 1
    on a different note, instead of trying to include a jar as dependency in all the microservices, a more common pattern with securing microservices would be to put a [gateway](https://roytuts.com/wp-content/uploads/2021/06/image.png) - e.g. [spring cloud gateway](https://spring.io/projects/spring-cloud-gateway) - in front of the microservices. Otherwise, spring-security dependencies will need to be included with every microservice. – indybee Feb 06 '22 at 12:31
  • It seems that you are manually doing what a resource server and authorization server do. If you use `spring-security-oauth2-resource-server` you can rely on it to validate the JWT, authenticate the user, and everything else by just providing the issuer-uri. Take a look at the spring-security-samples project on GitHub or at the reference docs – Marcus Hert da Coregio Feb 07 '22 at 14:28

0 Answers0