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
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
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"
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
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)
For example, with username admin and password admin, clients first combine the credentials into the string:
admin:admin
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;
}
}
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;
}
This snippet is critical.
If Basic Auth remains disabled, the request gets passed through unobstructed via:
chain.doFilter(request, response);
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");
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);
}
This block executes four sequential steps:
- Extract the full
Authorizationheader from the request - Strip the leading "Basic " prefix
- Base64-decode the remaining string content
- Split the decoded string on the colon symbol to separate username and password
Take this header as an example:
Authorization: Basic YWRtaW46YWRtaW4=
Decoding the Base64 segment yields the raw credential pair:
admin:admin
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;
}
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");
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
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
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
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"
}
}
}
After enabling Basic Auth, plain unauthenticated requests will fail:
curl http://localhost:8080/overview
Response:
401 Unauthorized
Two valid approaches to send authenticated requests:
- Short-form curl with built-in credential flag
curl -u admin:admin http://localhost:8080/overview
- Explicitly inject the Authorization header
curl \
-H "Authorization: Basic YWRtaW46YWRtaW4=" \
http://localhost:8080/overview
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)
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
);
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
);
}
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);
This method works seamlessly for both GET endpoints:
restTemplate.exchange(
"http://localhost:8080/running-jobs",
HttpMethod.GET,
new HttpEntity<Void>(null, headers),
List.class
);
And POST submission endpoints:
restTemplate.exchange(
"http://localhost:8080/submit-job",
HttpMethod.POST,
new HttpEntity<>(configText, headers),
Map.class
);
The core takeaway for client integration with Basic Auth-enabled Zeta Engine:
- No changes to REST API endpoints themselves
- No adjustments to API request paths
- 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:
-
enable-basic-authdefaults tofalse; REST APIs require no authentication when disabled - Once Basic Auth is toggled on, Zeta Engine intercepts all requests via the
BasicAuthFilter - Clients must attach the
Authorization: Basic [encoded-string]header to every request - The encoded segment is the Base64 output of the
username:passwordcredential pair - Default values for
basic-auth-usernameandbasic-auth-passwordare bothadmin - 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:
- Whether
enable-basic-authis enabled in your engine configuration - Whether your client request carries a valid Authorization header
- 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)