class JwtFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(@NonNull final HttpServletRequest request,
        @NonNull final HttpServletResponse response, @NonNull final FilterChain chain)
        throws ServletException, IOException {

        Claims claims = null;
        String token = "";

        if (!RequestMethod.OPTIONS.toString().equals(request.getMethod())) {

            final String authHeader = request.getHeader(HEADER_AUTHORIZATION);

            if (authHeader == null || !authHeader.startsWith(BEARER_PREFIX)) {
                LOGGER.info("Missing or invalid Authorization header.");
                claims = new DefaultClaims().setSubject(SUBJECT_ANONYMOUS);
            } else {
                try {
                    token = authHeader.substring(BEARER_PREFIX.length());
                    claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
                } catch (final JwtException e) {
                    LOGGER.warn("Unable to get claims from bearer token: {}", e.getMessage());
                }

                if (claims == null || claims.getSubject() == null) {
                    claims = new DefaultClaims().setSubject(SUBJECT_ANONYMOUS);
                }
            }

            request.setAttribute(JWT_ATTRIBUTE, claims);
            response.setHeader(JWT_TOKEN, token);
            response.setHeader(HEADER_CLAIMS, claims.toString());
            response.setHeader(HEADER_CLAIMS_SUBJECT, claims.getSubject());
            response.setHeader(HEADER_CLAIMS_USER_ID, claims.getId());
        }

        chain.doFilter(request, response);
    }

}