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

  1. Remove the Authorization header (and any credentials) from requests to key-transparency search, monitor, and distinguished-key endpoints
  2. Use a dedicated unauthenticated HTTP client for these endpoints
  3. If using an interceptor that adds auth globally, exclude these paths
  4. 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

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

Related errors


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)