# Jenkins Security Authentication Flow: How HudsonFilter and HttpSessionContextIntegrationFilter2 Work Together

> Explore the Jenkins security authentication flow. Learn how HudsonFilter and HttpSessionContextIntegrationFilter2 manage user authentication and maintain session state for secure access.

- Repository: [Jenkins/jenkins](https://github.com/jenkinsci/jenkins)
- Tags: internals
- Published: 2026-07-28

---

**Jenkins authenticates users through a two-filter architecture where `HudsonFilter` acts as the entry point for request processing and Stapler routing, while `HttpSessionContextIntegrationFilter2` persists the `Authentication` object in the HTTP session to maintain security context across stateless requests.**

Jenkins operates within a standard servlet container (Jetty, Tomcat, etc.) and delegates request-level security processing to a specialized filter chain. The **Jenkins security authentication flow** relies on two pivotal classes in the `hudson.security` package—`HudsonFilter` and `HttpSessionContextIntegrationFilter2`—to bridge the servlet container's HTTP handling with Jenkins' pluggable `SecurityRealm` architecture.

## HudsonFilter: The Request Entry Point

`HudsonFilter` serves as the primary servlet filter that intercepts every incoming request to Jenkins. Located in [`core/src/main/java/hudson/security/HudsonFilter.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/security/HudsonFilter.java), this filter initializes the Stapler request-routing engine and orchestrates the security filter chain.

The filter executes the following sequence in its `doFilter` method:

1. **Wraps the raw request** in a `StaplerRequest` to enable Jenkins' URL-to-method mapping
2. **Invokes `ChainedServletFilter2`** to sequentially execute security filters including `BasicAuthenticationFilter`, `AuthenticationProcessingFilter2`, and `CrumbFilter`
3. **Establishes the `SecurityContext`** by binding any valid `Authentication` object to the thread via `SecurityContextHolder`
4. **Dispatches to Stapler** for final handling by the appropriate Jenkins action or REST endpoint

```java
// Simplified flow inside HudsonFilter#doFilter
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
        throws IOException, ServletException {
    // 1. Wrap request for Stapler
    StaplerRequest staplerRequest = new StaplerRequestWrapper((HttpServletRequest) req);

    // 2. Run the Jenkins-specific filter chain
    chainedFilter.doFilter(staplerRequest, res, chain);

    // 3. Security context is now available for the rest of the request
    //    (e.g., Jenkins.getAuthentication())
}

```

## HttpSessionContextIntegrationFilter2: Session Security Bridge

While `HudsonFilter` handles request entry, `HttpSessionContextIntegrationFilter2` manages the persistence of authentication state across multiple HTTP requests. This filter, found in [`core/src/main/java/hudson/security/HttpSessionContextIntegrationFilter2.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/security/HttpSessionContextIntegrationFilter2.java), bridges the servlet container's HTTP session with Jenkins' security framework.

The filter performs three critical operations:

- **Retrieval**: On each request, it checks the HTTP session for an existing `SecurityContext` stored under the attribute key `HttpSessionContextIntegrationFilter2.SECURITY_CONTEXT_KEY`
- **Storage**: After successful authentication (performed by upstream filters like `BasicAuthenticationFilter`), it persists the `Authentication` object in the session
- **Thread binding**: It pushes the retrieved or created `SecurityContext` onto `SecurityContextHolder` so that `Jenkins.getAuthentication()` returns the current user throughout the request lifecycle

```java
// Core logic from HttpSessionContextIntegrationFilter2#doFilter
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
        throws IOException, ServletException {
    HttpServletRequest httpReq = (HttpServletRequest) req;
    HttpSession session = httpReq.getSession(false);

    // 1. Retrieve stored SecurityContext (if any)
    SecurityContext ctx = (session == null) ? null
            : (SecurityContext) session.getAttribute(
                HttpSessionContextIntegrationFilter2.SECURITY_CONTEXT_KEY);

    // 2. If request carries a new Authentication (post-login), store it
    if (SecurityContextHolder.getContext().getAuthentication() != null) {
        ctx = SecurityContextHolder.getContext();
        if (session != null) {
            session.setAttribute(
                HttpSessionContextIntegrationFilter2.SECURITY_CONTEXT_KEY, ctx);
        }
    }

    // 3. Bind context to thread for downstream processing
    try {
        SecurityContextHolder.setContext(ctx != null ? ctx : 
            SecurityContextHolder.createEmptyContext());
        chain.doFilter(req, res);
    } finally {
        SecurityContextHolder.clearContext();
    }
}

```

## End-to-End Authentication Sequence

Understanding how these filters interact reveals the complete **Jenkins security authentication flow**:

| Phase | Component | Action |
|-------|-----------|--------|
| **Initial Request** | `HudsonFilter` → `BasicAuthenticationFilter` | Extracts credentials (HTTP Basic, form data, or API token) and validates against the configured `SecurityRealm` (LDAP, Jenkins database, OAuth) |
| **Authentication** | `AuthenticationProcessingFilter2` | Creates an `Authentication` object upon successful credential validation |
| **Session Persistence** | `HttpSessionContextIntegrationFilter2` | Stores the `Authentication` in the HTTP session attribute `SECURITY_CONTEXT_KEY` |
| **Subsequent Requests** | `HudsonFilter` → `HttpSessionContextIntegrationFilter2` | Retrieves the stored `Authentication` from the session and binds it to `SecurityContextHolder` |
| **Authorization** | `AuthorizationStrategy` | Validates the current `Authentication` against permissions before allowing access to protected resources |

The filter order declared in Jenkins' generated [`web.xml`](https://github.com/jenkinsci/jenkins/blob/main/web.xml) ensures that `HttpSessionContextIntegrationFilter2` executes after authentication filters create the `Authentication` object but before any business logic requires the security context.

## Architectural Separation: Why Two Filters?

Jenkins separates these concerns to support both stateless API access and stateful web sessions:

- **`HudsonFilter`** provides a generic entry point that guarantees every request undergoes Stapler processing and security chain evaluation. It remains agnostic to session management, making it suitable for API calls that authenticate on every request without cookies.

- **`HttpSessionContextIntegrationFilter2`** isolates session-binding logic, allowing multiple authentication mechanisms (form login, basic auth, token-based) to reuse the same session persistence code without duplication.

This separation enables API clients to remain stateless while providing browser users with persistent login sessions through standard HTTP cookies.

## Practical Code Examples

### Registering a Custom SecurityRealm

```java
// In a Jenkins plugin's initialization code
@Extension
public class MyRealmPlugin extends Plugin {
    @Override
    public void start() throws Exception {
        Jenkins.get().setSecurityRealm(new MyCustomSecurityRealm());
        // Configure authorization strategy
        Jenkins.get().setAuthorizationStrategy(
            new GlobalMatrixAuthorizationStrategy());
    }
}

```

### Accessing the Current Authentication

```java
public class MyAction implements RootAction {
    @Override
    public String getDisplayName() {
        // Obtains user from SecurityContext populated by the filter chain
        Authentication auth = Jenkins.getAuthentication();
        User user = User.getById(auth.getName(), false);
        return "Hello, " + (user != null ? user.getFullName() : "anonymous");
    }
}

```

### Implementing Secure Logout

```java
public void doLogout(StaplerRequest req, StaplerResponse rsp) 
        throws IOException {
    HttpSession session = req.getSession(false);
    if (session != null) {
        session.removeAttribute(
            HttpSessionContextIntegrationFilter2.SECURITY_CONTEXT_KEY);
    }
    SecurityContextHolder.clearContext();  // Clear thread-local context
    rsp.sendRedirect2(req.getContextPath() + "/login");
}

```

## Summary

- **`HudsonFilter`** in [`hudson/security/HudsonFilter.java`](https://github.com/jenkinsci/jenkins/blob/main/hudson/security/HudsonFilter.java) acts as the mandatory entry point for all Jenkins requests, initializing Stapler and executing the security filter chain.
- **`HttpSessionContextIntegrationFilter2`** in [`hudson/security/HttpSessionContextIntegrationFilter2.java`](https://github.com/jenkinsci/jenkins/blob/main/hudson/security/HttpSessionContextIntegrationFilter2.java) maintains authentication state by storing and retrieving `SecurityContext` objects from the HTTP session.
- The **Jenkins security authentication flow** separates request processing from session management to support both stateless API clients and stateful browser sessions.
- Filter ordering in the servlet container ensures that `HttpSessionContextIntegrationFilter2` executes after authentication filters create credentials but before authorization checks occur.
- Developers can access the current authentication via `Jenkins.getAuthentication()`, which returns the `Authentication` object bound to the thread by these filters.

## Frequently Asked Questions

### How does `HttpSessionContextIntegrationFilter2` handle concurrent requests from the same user?

Each HTTP request executes in its own thread, and `HttpSessionContextIntegrationFilter2` retrieves the `SecurityContext` from the shared HTTP session at the start of each request. The filter binds this context to the thread-local `SecurityContextHolder`, ensuring thread isolation while allowing multiple simultaneous requests to share the same authentication credentials safely.

### Can Jenkins operate without `HttpSessionContextIntegrationFilter2`?

While technically possible for purely stateless API access, removing this filter would force users to re-authenticate on every single request, eliminating the ability to maintain login sessions via browser cookies. The filter is essential for the standard web UI experience where users expect to remain logged in across multiple page loads.

### Where does `HudsonFilter` fit in the standard servlet filter chain?

`HudsonFilter` is registered in the servlet container's [`web.xml`](https://github.com/jenkinsci/jenkins/blob/main/web.xml) (generated at runtime) and serves as the primary dispatch filter for all Jenkins URLs. It executes after container-level filters but before individual Jenkins components process the request, ensuring that `SecurityContext` is properly established regardless of whether the request targets a UI page, REST endpoint, or plugin resource.

### What happens to the security context when a session expires?

When the HTTP session expires or is invalidated, `HttpSessionContextIntegrationFilter2` cannot retrieve a stored `SecurityContext` on subsequent requests. The filter creates an empty context, causing `Jenkins.getAuthentication()` to return an anonymous or null authentication. The user must then re-authenticate through the configured `SecurityRealm` to establish a new valid session.