DEV Community

Apache SeaTunnel
Apache SeaTunnel

Posted on

How Basic Auth Works in Apache SeaTunnel Zeta Engine — Fix 401 Unauthorized API Errors

Recently while reviewing the REST API authentication logic of Apache SeaTunnel’s Zeta Engine, I ran into a very common issue:
The Zeta Engine fully started and its REST service listened on the designated port normally, yet accessing endpoints like /overview, /running-jobs and /job-info kept returning:

HTTP/1.1 401 Unauthorized
Enter fullscreen mode Exit fullscreen mode

If you encounter this error for the first time, you may easily assume the service failed to launch, you entered the wrong port number, or the API path is incorrect.

In reality, this error is mostly tied to the Basic Auth configuration of SeaTunnel Zeta Engine.
Once Basic Auth is enabled on Zeta Engine, clients can no longer send plain requests to REST APIs as before — valid authentication credentials must be attached in the request header.

Starting from this 401 error case, this article breaks down how Basic Auth operates inside SeaTunnel Zeta Engine, plus the correct client-side connection methods.

1. The Symptom: Receiving 401 When Calling Zeta REST APIs

Suppose we send a direct request to the Zeta Engine REST API:

curl http://localhost:8080/overview
Enter fullscreen mode Exit fullscreen mode

If Basic Auth stays disabled, this call will return the engine’s overview information without issues.

But after enabling Basic Auth in the config, requests missing authentication headers will trigger this response:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="SeaTunnel Web UI"
Enter fullscreen mode Exit fullscreen mode

This indicates the request successfully reached Zeta Engine, yet got intercepted by the authentication filter before hitting the actual REST Servlet.

To simplify the root cause chain:

Zeta Engine running normally
REST API endpoint fully functional
Client request missing Authorization header
Request intercepted by BasicAuthFilter → returns 401 error
Enter fullscreen mode Exit fullscreen mode

Basic Auth itself is a straightforward mechanism. Its core function is appending an authentication string to the HTTP Request Header:

Authorization: Basic base64(username:password)
Enter fullscreen mode Exit fullscreen mode

For example, with username admin and password admin, clients first combine the credentials into the string:

admin:admin
Enter fullscreen mode Exit fullscreen mode

Encode this string with Base64, then inject the encoded value into the Authorization header.

2. Source Code Deep Dive: How BasicAuthFilter Intercepts Requests

All core Basic Auth logic of SeaTunnel Zeta Engine resides in the BasicAuthFilter class.
This class implements the standard Java Servlet Filter interface:

public class BasicAuthFilter implements Filter {
    private final HttpConfig httpConfig;

    public BasicAuthFilter(HttpConfig httpConfig) {
        this.httpConfig = httpConfig;
    }
}
Enter fullscreen mode Exit fullscreen mode

The core trait of Servlet Filters: every request passes through the filter before reaching the target Servlet.
This means the Basic Auth validation logic is centralized in a universal filter, rather than hardcoded into individual API endpoints.

The core business logic lives in the doFilter method.
First, it checks whether Basic Auth has been toggled on:

if (!httpConfig.isEnableBasicAuth()) {
    chain.doFilter(request, response);
    return;
}
Enter fullscreen mode Exit fullscreen mode

This snippet is critical.
If Basic Auth remains disabled, the request gets passed through unobstructed via:

chain.doFilter(request, response);
Enter fullscreen mode Exit fullscreen mode

In short: REST APIs require zero authentication when enable-basic-auth is turned off.

When Basic Auth is enabled, the code proceeds to extract values from the HTTP request header:

HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;

String authHeader = httpRequest.getHeader("Authorization");
Enter fullscreen mode Exit fullscreen mode

Next, it verifies the header exists and follows the standard "Basic " prefix format:

if (authHeader != null && authHeader.startsWith("Basic ")) {
    String base64Credentials = authHeader.substring("Basic ".length());
    String credentials =
            new String(Base64.decodeBase64(base64Credentials), StandardCharsets.UTF_8);

    final String[] values = credentials.split(":", 2);
}
Enter fullscreen mode Exit fullscreen mode

This block executes four sequential steps:

  1. Extract the full Authorization header from the request
  2. Strip the leading "Basic " prefix
  3. Base64-decode the remaining string content
  4. Split the decoded string on the colon symbol to separate username and password

Take this header as an example:

Authorization: Basic YWRtaW46YWRtaW4=
Enter fullscreen mode Exit fullscreen mode

Decoding the Base64 segment yields the raw credential pair:

admin:admin
Enter fullscreen mode Exit fullscreen mode

The code then compares the parsed credentials against the values defined in the engine configuration:

if (username.equals(httpConfig.getBasicAuthUsername())
        && password.equals(httpConfig.getBasicAuthPassword())) {
    chain.doFilter(request, response);
    return;
}
Enter fullscreen mode Exit fullscreen mode

Requests matching the configured username and password pass through the filter successfully.

If the header is missing, malformed, or contains mismatched credentials, the filter returns a 401 error response:

httpResponse.setHeader("WWW-Authenticate", "Basic realm=\"SeaTunnel Web UI\"");
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
Enter fullscreen mode Exit fullscreen mode

The full execution flow of BasicAuthFilter can be summarized as:

Client request arrives at Zeta REST service
        ↓
Check if Basic Auth is enabled in configuration
        ↓
Disabled: Forward request directly to target API
        ↓
Enabled: Extract the Authorization header from HTTP request
        ↓
Parse and Base64-decode credentials to retrieve username + password
        ↓
Compare parsed credentials against configured username & password
        ↓
Credentials match: Forward request to target API
Credentials mismatch / invalid header: Return 401 Unauthorized
Enter fullscreen mode Exit fullscreen mode

3. Configuration Breakdown: How enable-basic-auth, username and password Take Effect

Three core configuration items govern Basic Auth functionality:
By default, the configuration values are set as follows:

enable-basic-auth = false
basic-auth-username = admin
basic-auth-password = admin
Enter fullscreen mode Exit fullscreen mode

A key detail to note:
Even though basic-auth-username and basic-auth-password default to admin, these two fields do nothing unless enable-basic-auth is activated.

The single switch controlling authentication enforcement is:

enable-basic-auth
Enter fullscreen mode Exit fullscreen mode

When set to false, all Zeta Engine REST APIs operate without authentication requirements.
When set to true, every request routed through BasicAuthFilter must carry valid authentication credentials.

A complete sample configuration block:

seatunnel {
  engine {
    http {
      enable-http = true
      port = 8080

      enable-basic-auth = true
      basic-auth-username = "admin"
      basic-auth-password = "admin"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

After enabling Basic Auth, plain unauthenticated requests will fail:

curl http://localhost:8080/overview
Enter fullscreen mode Exit fullscreen mode

Response:

401 Unauthorized
Enter fullscreen mode Exit fullscreen mode

Two valid approaches to send authenticated requests:

  1. Short-form curl with built-in credential flag
curl -u admin:admin http://localhost:8080/overview
Enter fullscreen mode Exit fullscreen mode
  1. Explicitly inject the Authorization header
curl \
  -H "Authorization: Basic YWRtaW46YWRtaW4=" \
  http://localhost:8080/overview
Enter fullscreen mode Exit fullscreen mode

The string YWRtaW46YWRtaW4= is the Base64 encoding of the credential pair admin:admin.

4. Client Implementation: Connect via the Authorization Header

Once you grasp the server-side authentication workflow, the client-side requirements become clear:
If Zeta Engine has Basic Auth enabled, every REST API request sent by the client must include this header:

Authorization: Basic base64(username:password)
Enter fullscreen mode Exit fullscreen mode

For Java client implementations, you can leverage Spring’s built-in HttpHeaders#setBasicAuth to auto-generate the header without manual Base64 encoding:

HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("admin", "admin", StandardCharsets.UTF_8);

HttpEntity<Void> entity = new HttpEntity<>(headers);

ResponseEntity<Map> response = restTemplate.exchange(
        "http://localhost:8080/overview",
        HttpMethod.GET,
        entity,
        Map.class
);
Enter fullscreen mode Exit fullscreen mode

For reusable code, wrap the authentication logic into a dedicated helper method:

private void applyBasicAuth(HttpHeaders headers, String username, String password) {
    if (username == null || username.trim().isEmpty()) {
        return;
    }

    if (password == null || password.trim().isEmpty()) {
        return;
    }

    headers.setBasicAuth(
            username.trim(),
            password,
            StandardCharsets.UTF_8
    );
}
Enter fullscreen mode Exit fullscreen mode

Invoke this utility method before every REST API call to attach authentication universally:

HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

applyBasicAuth(headers, username, password);
Enter fullscreen mode Exit fullscreen mode

This method works seamlessly for both GET endpoints:

restTemplate.exchange(
        "http://localhost:8080/running-jobs",
        HttpMethod.GET,
        new HttpEntity<Void>(null, headers),
        List.class
);
Enter fullscreen mode Exit fullscreen mode

And POST submission endpoints:

restTemplate.exchange(
        "http://localhost:8080/submit-job",
        HttpMethod.POST,
        new HttpEntity<>(configText, headers),
        Map.class
);
Enter fullscreen mode Exit fullscreen mode

The core takeaway for client integration with Basic Auth-enabled Zeta Engine:

  1. No changes to REST API endpoints themselves
  2. No adjustments to API request paths
  3. Only mandatory addition: the Authorization request header

Summary

The Basic Auth implementation inside SeaTunnel Zeta Engine is lightweight, yet it frequently triggers confusing 401 errors for first-time users.

Core takeaways condensed into six key points:

  1. enable-basic-auth defaults to false; REST APIs require no authentication when disabled
  2. Once Basic Auth is toggled on, Zeta Engine intercepts all requests via the BasicAuthFilter
  3. Clients must attach the Authorization: Basic [encoded-string] header to every request
  4. The encoded segment is the Base64 output of the username:password credential pair
  5. Default values for basic-auth-username and basic-auth-password are both admin
  6. SeaTunnel Web delivers a visual interface to simplify authentication setup and engine connection workflows

When you encounter a 401 Unauthorized response, avoid jumping to conclusions that the Zeta Engine failed to start or that your port/path values are incorrect.
Prioritize verifying these three points first:

  1. Whether enable-basic-auth is enabled in your engine configuration
  2. Whether your client request carries a valid Authorization header
  3. Whether the username and password match the values defined in the engine config

With this authentication workflow fully understood, troubleshooting and integrating with SeaTunnel Zeta Engine’s REST APIs becomes far more straightforward.

Top comments (0)