signalapp/Signal-Server · error · BadRequestException
Endpoint requires unauthenticated access
Error message
Endpoint requires unauthenticated access
What it means
KeyTransparencyController.requireNotAuthenticated enforces that certain key-transparency endpoints (search, monitor, getDistinguishedKey) are called WITHOUT account credentials, mirroring the privacy design of the protocol. If an AuthenticatedDevice is present in the request context it throws BadRequestException('Endpoint requires unauthenticated access').
Solutions
- Remove the Authorization header (and any credentials) from requests to key-transparency search, monitor, and distinguished-key endpoints
- Use a dedicated unauthenticated HTTP client for these endpoints
- If using an interceptor that adds auth globally, exclude these paths
- Call the endpoints from an unauthenticated (e.g. new, credential-less) connection
Example fix
// before
authenticatedClient.get("/v1/key-transparency/search?..."); // 400 BadRequestException
// after
Request req = new Request.Builder().url(searchUrl).build(); // no Authorization header
unauthenticatedClient.newCall(req).execute(); Defensive patterns
Strategy: validation
Validate before calling
if (request.getHeader("Authorization") != null) {
throw new IllegalStateException("key-transparency endpoints must be called without credentials");
} Type guard
boolean isUnauthenticated(Request r) { return r.header("Authorization") == null; } Try / catch
try {
return client.search(...);
} catch (WebApplicationException e) {
if (e.getResponse().getStatus() == 400 && e.getMessage().contains("unauthenticated")) {
// drop Authorization header and retry once
} else throw e;
} Prevention
- Use a separate unauthenticated HTTP client for key-transparency calls
- Exclude these paths from global auth interceptors
- Never reuse logged-in sessions for anonymous endpoints
When it happens
Trigger: Calling GET/POST on the key-transparency search, monitor, or distinguished-key endpoints while sending an Authorization header / authenticated session that resolves to an AuthenticatedDevice.
Common situations: A shared HTTP client automatically attaches auth headers to all requests; developers testing with their logged-in session; proxy/SDK that injects credentials globally.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Operation requires unauthenticated access
- recovery password could not be verified
- must not use authenticated connection for anonymous…
- must not use authenticated connection for call quality…
- login purchases are not enabled
AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09).
Data as JSON: /api/errors/d564e51fe2adacb0.
Report an issue: GitHub.
Appendix: source
Thrown at service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeyTransparencyController.java:252
}
private void handleKeyTransparencyServiceError(final StatusRuntimeException exception) {
final Status.Code code = exception.getStatus().getCode();
final String description = exception.getStatus().getDescription();
switch (code) {
case NOT_FOUND -> throw new NotFoundException(description);
case PERMISSION_DENIED -> throw new ForbiddenException(description);
case INVALID_ARGUMENT -> throw new WebApplicationException(description, 422);
default -> {
LOGGER.error("Unexpected error calling key transparency service", exception);
throw new ServerErrorException(Response.Status.INTERNAL_SERVER_ERROR, exception);
}
}
}
private void requireNotAuthenticated(final Optional<AuthenticatedDevice> authenticatedAccount) {
if (authenticatedAccount.isPresent()) {
throw new BadRequestException("Endpoint requires unauthenticated access");
}
}
}
View on GitHub (pinned to 100ab61c82)