Implementing Authentication, Logging, and Request Filters in Java Servlets
Course: Advanced Java Training
Topic: Implementing Authentication, Logging, and Request Filters
Course Link: Advanced Java Training Course
Demo Link: Register for a Course Demo
Website: JustAcademy Official Website
1. Introduction
Authentication, logging, and request filtering are important components of secure Java web application development. They help developers verify user identity, monitor application activity, inspect incoming requests, and control whether requests should reach protected resources.
In Java Servlet applications, filters provide a reusable mechanism for processing HTTP requests and responses before and after a servlet or other web resource executes. Common applications include authentication checks, request logging, auditing, security headers, and request validation.
These three concepts work together:
- Authentication: Verifies who the user is.
- Logging: Records relevant application and request activity for debugging, monitoring, and auditing.
- Request filtering: Intercepts requests and responses to apply common processing rules.
2. Learning Objectives
After completing this topic, learners should be able to:
- Understand the role of authentication in web applications.
- Differentiate authentication from authorization.
- Implement a basic session-based authentication filter.
- Use the Jakarta Servlet
Filter interface.
- Record HTTP request details and response status information.
- Configure filters using annotations and
web.xml.
- Understand filter chaining and execution order.
- Apply basic security practices to authentication and logging.
- Test protected resources, unauthenticated requests, and filter behavior.
3. Understanding Authentication
Authentication is the process of verifying the identity of a user, application, or client. In a typical web application, users provide credentials through a login form, and the server verifies those credentials against a trusted identity source.
After successful authentication, the application may create an authenticated session so that the user does not have to submit credentials with every request.
Common Authentication Methods
| Method |
Description |
Typical Use |
| Form-based authentication |
Users submit credentials through a login page. |
Web applications and dashboards. |
| Session-based authentication |
The server maintains authenticated state in an HTTP session. |
Traditional Java Servlet applications. |
| HTTP Basic authentication |
Credentials are sent using the HTTP Authorization header. |
Limited internal services and protected APIs when used with HTTPS. |
| Token-based authentication |
Requests contain a token that the server validates. |
REST APIs and distributed applications. |
| Single sign-on (SSO) |
A trusted identity provider authenticates users across applications. |
Enterprise environments. |
4. Authentication vs. Authorization
Authentication and authorization are related but different security processes.
| Authentication |
Authorization |
| Determines who the user is. |
Determines what the user is permitted to do. |
| Usually occurs during login or credential validation. |
Occurs when checking access to a resource or operation. |
| May establish an authenticated session. |
Uses roles, permissions, ownership rules, or policies. |
| Example: verifying a user's password. |
Example: allowing only administrators to delete users. |
A user being authenticated does not automatically mean that the user can access every resource. Applications must enforce authorization checks separately.
5. What Is a Servlet Filter?
A servlet filter is a Java component that intercepts requests and responses as they pass through the servlet container. It can inspect request information, perform processing, stop a request, wrap request or response objects, or allow processing to continue to the next filter or target resource.
Filters are defined using the jakarta.servlet.Filter interface and are commonly mapped to URL patterns or specific servlet resources.
Important Filter Methods
| Method |
Purpose |
init(FilterConfig config) |
Initializes the filter when the container places it into service. |
doFilter(ServletRequest request, ServletResponse response, FilterChain chain) |
Processes each matching request and response. |
destroy() |
Allows cleanup when the filter is taken out of service. |
chain.doFilter(request, response) |
Passes control to the next filter or the requested resource. |
6. Understanding the Filter Lifecycle
The servlet container manages the lifecycle of a filter.
- Filter creation: The container creates the filter instance.
- Initialization: The container calls
init() when the filter is initialized.
- Request processing: For matching requests, the container invokes
doFilter().
- Chain execution: The filter either stops the request or invokes
chain.doFilter().
- Cleanup: The container calls
destroy() when the filter is taken out of service.
7. Creating a Basic Request Logging Filter
A logging filter records useful details about incoming requests and completed responses. It can help developers understand traffic patterns, diagnose errors, and monitor application performance.
The following example records the HTTP method, requested path, response status, and processing duration. It intentionally avoids logging passwords, cookies, authorization headers, and request bodies.
package com.example.filter;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.logging.Logger;
@WebFilter("/*")
public class RequestLoggingFilter implements Filter {
private static final Logger LOGGER =
Logger.getLogger(RequestLoggingFilter.class.getName());
@Override
public void init(FilterConfig config) {
LOGGER.info("RequestLoggingFilter initialized");
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
long startTime = System.nanoTime();
HttpServletRequest httpRequest =
(HttpServletRequest) request;
HttpServletResponse httpResponse =
(HttpServletResponse) response;
String method = httpRequest.getMethod();
String path = httpRequest.getRequestURI();
try {
chain.doFilter(request, response);
} finally {
long durationMs =
(System.nanoTime() - startTime) / 1_000_000;
LOGGER.info(() ->
"method=" + method
+ ", path=" + path
+ ", status=" + httpResponse.getStatus()
+ ", durationMs=" + durationMs
);
}
}
@Override
public void destroy() {
LOGGER.info("RequestLoggingFilter destroyed");
}
}
Code Explanation
@WebFilter("/*") maps the filter to all matching URL paths in the application.
HttpServletRequest provides HTTP-specific information such as the request method and URI.
System.nanoTime() measures elapsed processing time.
chain.doFilter() allows the request to continue to the next filter or target resource.
- The
finally block logs the request even if downstream processing throws an exception.
getStatus() reports the response status available when the filter reads it.
Important: This is an educational example using Java's built-in logging API. Production applications may use SLF4J with Logback or another configured logging framework. Ensure that logging configuration, access controls, retention, and sensitive-data handling meet the application's requirements.
8. What Information Should a Logging Filter Capture?
A useful logging filter records enough information to understand request behavior without collecting unnecessary personal or confidential data.
| Field |
Purpose |
Guidance |
| HTTP method |
Identifies GET, POST, PUT, DELETE, and other methods. |
Generally appropriate to record. |
| Request path |
Shows which resource was requested. |
Avoid logging sensitive query parameters. |
| Response status |
Helps identify successful and failed requests. |
Record the status after downstream processing. |
| Duration |
Helps identify slow requests. |
Use a monotonic timer such as System.nanoTime(). |
| Correlation ID |
Connects related log entries. |
Validate or generate IDs rather than trusting arbitrary client input. |
| User identifier |
May support auditing authenticated activity. |
Record only when necessary and permitted by policy. |
Avoid recording passwords, authentication tokens, session IDs, full payment details, and sensitive personal data. Query strings may also contain private information, so log paths separately from query parameters unless there is a justified and secure reason to retain them.
9. Implementing a Session-Based Authentication Filter
An authentication filter can protect resources by checking whether an authenticated user exists in the current session. If no authenticated session is found, the filter can redirect the browser to a login page or return an unauthorized response for an API request.
This example assumes that a trusted login process stores a server-validated user identifier in the session under the attribute authenticatedUser.
package com.example.filter;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter("/secure/*")
public class AuthenticationFilter implements Filter {
@Override
public void init(FilterConfig config) {
// Initialize required filter configuration here.
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest =
(HttpServletRequest) request;
HttpServletResponse httpResponse =
(HttpServletResponse) response;
HttpSession session = httpRequest.getSession(false);
boolean authenticated =
session != null
&& session.getAttribute("authenticatedUser") != null;
if (!authenticated) {
String loginPath =
httpRequest.getContextPath() + "/login.html";
httpResponse.sendRedirect(loginPath);
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
// Release resources if necessary.
}
}
How the Authentication Filter Works
- The filter is mapped to URLs under
/secure/*.
- It checks for an existing session using
getSession(false).
- It checks for the expected authenticated-user attribute.
- If the session or attribute is missing, it redirects to the login page.
- If authentication state exists, it passes the request to the next filter or resource.
Security note: The session attribute must be created only after credentials have been validated by a trusted authentication process. This simple check demonstrates the filter pattern; it is not a complete identity-management system. Production applications should use a framework or container-managed security where appropriate and must enforce authorization independently.
10. Creating a Login Servlet
A login servlet receives credentials, validates them using a trusted authentication service, and establishes authenticated session state only after successful verification.
The following example shows the flow using an illustrative AuthenticationService. The service is responsible for verifying credentials securely against a trusted identity store. It must not accept arbitrary usernames or passwords as valid.
package com.example.auth;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private final AuthenticationService authenticationService =
new AuthenticationService();
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if (username == null || password == null
|| username.isBlank() || password.isBlank()) {
response.sendError(
HttpServletResponse.SC_BAD_REQUEST,
"Username and password are required."
);
return;
}
// Illustrative service: implement secure credential validation.
AuthenticatedUser user =
authenticationService.authenticate(username, password);
if (user == null) {
response.sendError(
HttpServletResponse.SC_UNAUTHORIZED,
"Invalid username or password."
);
return;
}
HttpSession oldSession = request.getSession(false);
if (oldSession != null) {
oldSession.invalidate();
}
HttpSession newSession = request.getSession(true);
newSession.setAttribute("authenticatedUser", user.getId());
newSession.setMaxInactiveInterval(15 * 60);
response.sendRedirect(
request.getContextPath() + "/secure/dashboard"
);
}
}
Implementation note: AuthenticationService and AuthenticatedUser are illustrative application classes and must be implemented separately. Credential validation should use an established password-hashing mechanism, safe database access, rate limiting, and generic error messages. The example invalidates an old session before creating a fresh authenticated session, helping reduce session-fixation risk. For a fully developed application, consider the supported session-ID rotation mechanism and the authentication framework in use.
11. Protecting Against Session Fixation
Session fixation is a security risk in which an attacker attempts to make a victim use a session identifier known to the attacker. If the session identifier remains unchanged after login, the attacker may be able to reuse it under certain conditions.
Recommended protections include:
- Rotate the session ID after successful authentication using
request.changeSessionId() when supported and appropriate.
- Alternatively, invalidate the pre-authentication session and establish a new session while preserving only necessary, safe state.
- Use HTTPS for the entire authenticated session.
- Configure session cookies with appropriate
Secure, HttpOnly, and SameSite attributes.
- Never accept a user-supplied session attribute as proof of authentication without trusted server-side validation.
Example of Session ID Rotation
// Call only after successful authentication.
HttpSession session = request.getSession(true);
request.changeSessionId();
session.setAttribute("authenticatedUser", authenticatedUserId);
Use this approach according to the application's servlet version and authentication flow. Do not combine different session-renewal approaches without understanding how they affect stored session data.
12. Adding Security Headers with a Filter
A response filter can set appropriate HTTP security headers for matching resources. The exact headers should be selected according to the application's content, authentication mechanisms, and deployment architecture.
package com.example.filter;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/*")
public class SecurityHeadersFilter implements Filter {
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpResponse =
(HttpServletResponse) response;
httpResponse.setHeader(
"X-Content-Type-Options", "nosniff"
);
httpResponse.setHeader(
"Referrer-Policy", "strict-origin-when-cross-origin"
);
httpResponse.setHeader(
"Content-Security-Policy",
"default-src 'self'; object-src 'none'; base-uri 'self'"
);
chain.doFilter(request, response);
}
}
Important: The Content Security Policy shown is a basic starting point. Real applications may need additional directives for scripts, styles, images, APIs, and other resources. Test policies carefully before production deployment. Configure HTTP Strict Transport Security only when the application is correctly deployed over HTTPS and the policy is appropriate for the domain.
13. Understanding Filter Chaining
Multiple filters can be applied to a single request. The servlet container invokes the matching filters in a configured order. Each filter can perform work before and after calling chain.doFilter().
For example, an application may use the following sequence:
- Request logging filter: Records request arrival.
- Security headers filter: Sets applicable response headers.
- Authentication filter: Checks whether the user has an authenticated session.
- Authorization check: Verifies permission to access a specific resource.
- Servlet: Processes the request.
In practice, security headers may need to be set before an authentication filter redirects or rejects a request. Logging should also be arranged so that rejected requests are recorded. Filter ordering must be tested because annotation-based ordering is not a substitute for an explicit ordering requirement.
Filter Chain Flow
Client Request
|
v
Request Logging Filter
|
v
Security Headers Filter
|
v
Authentication Filter
|
+---- Not authenticated ----> Redirect / 401 / 403
|
v
Authorization Check
|
v
Target Servlet or Resource
|
v
Response returns through filter chain
|
v
Client Response
14. Configuring Filters with @WebFilter
The @WebFilter annotation declares a filter and specifies which URL patterns it should process.
Example
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.Filter;
@WebFilter(urlPatterns = {"/secure/*", "/admin/*"})
public class ProtectedAreaFilter implements Filter {
// Implement doFilter() and other required lifecycle methods.
}
This mapping applies the filter to requests that match the specified URL patterns. It does not automatically guarantee that the user has a particular role; the filter must perform the appropriate checks or delegate security enforcement to a trusted framework.
15. Configuring Filters with web.xml
Filters can also be configured using the deployment descriptor, web.xml. This approach is useful when filter declarations and their order need to be managed centrally.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<filter>
<filter-name>RequestLoggingFilter</filter-name>
<filter-class>com.example.filter.RequestLoggingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RequestLoggingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>AuthenticationFilter</filter-name>
<filter-class>com.example.filter.AuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthenticationFilter</filter-name>
<url-pattern>/secure/*</url-pattern>
</filter-mapping>
</web-app>
When using web.xml, confirm that the declared filter class names match the actual packages and classes in the application. The schema version must also match the servlet API supported by the target container. Avoid accidentally registering the same filter through both annotations and the deployment descriptor.
16. Logging Authentication and Security Events
Security logging records events that may be important for investigation, compliance, and troubleshooting. Authentication-related events can include successful login, failed login, logout, session expiration, and access-denied outcomes.
| Event |
Useful Log Details |
Information to Avoid |
| Successful login |
Timestamp, result, safe user identifier, correlation ID. |
Password, session ID, access token. |
| Failed login |
Timestamp, generic failure category, rate-limit outcome. |
Submitted password or secret credentials. |
| Logout |
Timestamp, event type, safe user identifier when available. |
Cookie values or authentication tokens. |
| Access denied |
Requested resource, status, policy outcome. |
Unnecessary confidential request parameters. |
| Application error |
Correlation ID, error category, controlled diagnostic details. |
Secrets, private payloads, or exposed stack traces in public responses. |
Use structured logging where practical, synchronize timestamps across application systems, restrict access to logs, and define retention and deletion policies. Treat client-controlled values as untrusted input and sanitize them to prevent log injection.
17. Returning Correct HTTP Status Codes
Authentication filters must distinguish between browser navigation and API requests. Redirecting a browser to a login page may be appropriate for a traditional web application, whereas an API usually returns a status code and a suitable response body.
| Status Code |
Meaning |
Common Situation |
200 OK |
Request succeeded. |
Successful response from an accessible resource. |
302 Found |
Temporary redirect. |
Redirecting a browser to a login page. |
401 Unauthorized |
Valid authentication credentials are missing or unacceptable. |
Unauthenticated API request. |
403 Forbidden |
The server refuses access to the resource. |
An authenticated user lacks the required permission. |
500 Internal Server Error |
Unexpected server-side failure. |
Unhandled application error. |
The precise response should reflect the application's authentication scheme and API contract. HTTP 401 responses using an HTTP authentication scheme may require a suitable WWW-Authenticate challenge. Do not use a 403 response as a substitute for every authentication failure.
18. Common Errors and Troubleshooting
| Problem |
Possible Cause |
Solution |
| Filter never executes |
Incorrect URL mapping or annotation scanning configuration. |
Verify the URL pattern, package, servlet container, and deployment settings. |
| Every request redirects to login |
The login process does not set the expected session attribute, or the session is not preserved. |
Verify successful credential validation, attribute names, cookie behavior, and context path. |
| Protected page is accessible without login |
The filter is mapped to the wrong paths or some endpoints bypass the check. |
Audit all protected routes and enforce security consistently. |
| Requests stop unexpectedly |
chain.doFilter() is not called on an allowed request. |
Call the chain after successful checks. |
| Duplicate log entries |
Filter is registered more than once or mapped to overlapping processing paths. |
Review annotation and deployment-descriptor configuration. |
| Incorrect response status in logs |
The status is recorded before downstream processing completes. |
Record the status after chain.doFilter() returns, while accounting for exceptions and response wrappers. |
| Sensitive information appears in logs |
Credentials, headers, query strings, or payloads are being logged. |
Remove sensitive fields and review logging configuration and retention. |
| Filter order is unexpected |
Order was assumed from class names or annotations. |
Configure and verify filter mappings explicitly when ordering matters. |
19. Practical Exercises
Exercise 1: Create a Request Logging Filter
- Create a class that implements
Filter.
- Map it to a set of application URLs.
- Record the request method, path, response status, and elapsed time.
- Verify that errors and rejected requests are logged appropriately.
Exercise 2: Protect a Dashboard
- Create a login form and a server-side credential validation flow.
- Create an authenticated session after successful login.
- Implement a filter for the
/secure/* path.
- Redirect browser requests without valid authentication to the login page.
- Test access before login, after login, and after logout.
Exercise 3: Configure Security Headers
- Create a response filter.
- Set appropriate content-type and referrer policy headers.
- Configure and test a Content Security Policy.
- Inspect responses using browser developer tools.
Exercise 4: Test Filter Order
- Create two filters that log messages before and after the chain call.
- Configure their mappings in the deployment descriptor.
- Observe the order in which the filters execute.
- Explain why the response processing order is the reverse of the entry order for a simple nested chain.
20. Mini Project: Secure Employee Management Application
Objective: Build a Java Servlet application that uses authentication, request logging, and filters to protect employee management pages.
Functional Requirements
- Create a login page and validate credentials against a trusted identity source.
- Create an authenticated session after successful login.
- Protect employee dashboard and management routes.
- Record request method, path, status, and processing duration.
- Log login success, login failure, logout, and access-denied events safely.
- Invalidate the session during logout.
- Set a reasonable session inactivity timeout.
- Apply suitable security response headers.
- Implement authorization so only users with the appropriate role can perform administrative actions.
- Test direct URL access, invalid sessions, and unauthorized operations.
Expected Outcome
The application should distinguish authenticated and unauthenticated requests, apply authorization rules to protected operations, and generate useful logs without exposing secrets. The filters should be reusable and easy to maintain.
21. Interview Questions and Answers
Q1. What is a servlet filter?
A servlet filter is a reusable component that can inspect or modify requests and responses before or after a target resource processes them.
Q2. What is the purpose of the doFilter() method?
It contains the main filtering logic. A filter can reject a request or call chain.doFilter() to continue processing.
Q3. What is authentication?
Authentication verifies the identity of a user or client.
Q4. What is authorization?
Authorization determines whether an authenticated identity is allowed to access a resource or perform an operation.
Q5. Why is logging useful in a web application?
Logging helps diagnose errors, monitor application behavior, investigate incidents, and audit important events.
Q6. How can a filter protect a URL?
The filter checks the request's authentication state and either allows processing to continue or blocks access by redirecting or returning an appropriate HTTP response.
Q7. What is the purpose of chain.doFilter()?
It passes the request and response to the next filter or the target resource in the filter chain.
Q8. What is session-based authentication?
It maintains authenticated state on the server in an HTTP session that is associated with subsequent requests.
Q9. Why should passwords not be logged?
Logs may be accessible to more people and systems than credential stores. Recording passwords creates unnecessary exposure and can compromise user accounts.
Q10. What is session fixation?
Session fixation is an attack in which a victim is induced to use a session identifier known to an attacker. Rotating the session ID after authentication or safely replacing the session helps mitigate this risk.
Q11. How do you configure a filter?
A filter can be declared using @WebFilter or configured through the application's web.xml deployment descriptor.
Q12. Can multiple filters process one request?
Yes. Multiple filters can be mapped to the same resource and execute in a configured order.
Q13. Should every authenticated user have administrator access?
No. Authentication establishes identity, while authorization determines which resources and actions are permitted.
Q14. What is the difference between a 401 and a 403 response?
A 401 response indicates missing or unacceptable authentication credentials, while a 403 response indicates that the server refuses access to the requested resource.
Q15. What should a secure request logger avoid recording?
It should avoid passwords, access tokens, session identifiers, authorization headers, and unnecessary sensitive personal information.
22. Quick Revision Checklist
- Understand authentication and authorization as separate concepts.
- Know the lifecycle methods of the
Filter interface.
- Use
chain.doFilter() to continue permitted requests.
- Map filters using
@WebFilter or web.xml.
- Check authentication state before serving protected resources.
- Create authenticated sessions only after successful credential validation.
- Apply authorization checks to protected operations.
- Record useful request metadata without logging secrets.
- Use HTTPS and secure session cookie settings.
- Rotate or replace sessions safely after authentication.
- Test filter mappings, execution order, redirects, and error responses.
23. Conclusion
Authentication, logging, and request filters are essential building blocks for secure and maintainable Java Servlet applications. Authentication verifies identity, authorization controls access, and logging provides visibility into application activity. Servlet filters make it possible to apply reusable processing rules across multiple endpoints without duplicating the same code in every servlet.
When implementing these features, developers should use trusted credential validation, appropriate session management, explicit authorization rules, careful filter configuration, and privacy-conscious logging. These practices help create reliable applications that are easier to troubleshoot, monitor, and secure.
Continue learning enterprise Java development through the Advanced Java Training Course. You can also register for a course demo or visit the JustAcademy website.