Skip to content
SDKs · JavaIn development

Java

The server→server Background-Check client for any JVM service (Java 17+). Mint a challenge, appraise the client's opaque evidence with your rh_sk_ secret key, and get the verdict back directly in the response. Built on the JDK HttpClient — no third-party HTTP dependency.

In development

This SDK is implemented but not yet published to its package registry. Until it ships, collect an opaque evidence blob on the device and appraise it server-side with @rootherald/node (or any available server SDK). The API shown below is the planned surface and may change before release.

How it works

Your keyless client collects an opaque evidence blob and hands it to your backend. Your backend uses BackgroundCheckClient, authenticated with its rh_sk_ secret, to mint a nonce (issueChallenge) and submit the evidence for appraisal (verify). The verdict is computed by RootHerald and returned to your backend — it never travels through the client, which holds no key.

1

Install

<!-- Maven -->
<dependency>
  <groupId>io.rootherald</groupId>
  <artifactId>rootherald-client</artifactId>
  <version>0.1.0</version>
</dependency>
// Gradle (Kotlin DSL)
implementation("io.rootherald:rootherald-client:0.1.0")
2

Build the client

import io.rootherald.client.BackgroundCheckClient;

// Build once; uses the JDK HttpClient, no third-party HTTP dependency.
// secretKey (rh_sk_…) is validated — a non-rh_sk_ value is rejected.
var rh = BackgroundCheckClient.builder()
    .secretKey(System.getenv("RH_SECRET_KEY"))
    .build();
3

Mint a challenge

import io.rootherald.client.Challenge;

// Mint a nonce and relay it to your client; it quotes over challenge.nonce()
// and returns an opaque evidence blob to your backend.
Challenge challenge = rh.issueChallenge();
4

Verify the evidence

verify returns an AttestResult: a normalised verdict() string, isAllowed(), and the full verdictNode() (which also carries advisory-only cohort accessors like cohortPrevalence()).

import io.rootherald.client.AttestOptions;
import io.rootherald.client.AttestResult;

// 'evidence' is the opaque JSON string your client collected, passed through
// verbatim. Only protocol/auth/quota problems throw — a failing device does not.
AttestResult result = rh.verify(evidence, AttestOptions
    .of(challenge.challengeId())
    .policy("rootherald:builtin:strict-hardware"));

if (!result.isAllowed()) {           // verdict() is "allow" | "deny" | "review"
    return ResponseEntity.status(403).build();
}

// The full verdict is on result.verdictNode(); read the stable device id from it.
String deviceId = result.verdictNode().path("device").path("ueid").asText();

Errors

try {
    rh.verify(evidence, AttestOptions.of(challengeId));
} catch (QuotaExceededException e) {   // 429 — back off and retry later
} catch (InvalidSecretKeyException e) { // 401 — check the rh_sk_ key
} catch (UnknownPolicyException e) {    // 422 — fix the policy name
} catch (RootHeraldException e) {       // catch-all base for protocol/auth failures
}

A real-but-rejected device is not an exception — branch on result.verdict() instead.

Sample

A runnable Spring Boot demo that calls the client from a controller lives at RootHerald/sdk-java/samples/spring-boot-demo.