Skip to content
XID

sdk/java

Java 17+ server SDK for networkless JWT verification, HTTP request authentication, and webhook signature validation.

Status

Implemented and verified locally. Real IdP round-trip verification (JWKS fetch, token sign/verify against a live XID instance) has not been performed yet and must be completed before production use.

XID publishes no packages to any registry. This SDK is distributed as source in the XID repository; use it from a checkout of the repository.

Request authentication is Bearer-only by default. An application-owned JWT cookie is read only when its exact name is configured. The opaque __Host-xid.rt.* Core cookie is never scanned or verified locally; exchange it by forwarding the complete Cookie header to exact same-origin POST /v1/sessions/token with redirects disabled, and accept only a response containing the token field.

Install

Java 17+ and Maven required.

<!-- First install the source checkout: cd sdk/java && mvn install -->
<dependency>
  <groupId>dev.xid</groupId>
  <artifactId>xid-sdk-java</artifactId>
  <version>0.1.0-alpha.0</version>
</dependency>

Quick start

Construct one XidClient at application startup and use it as a singleton.

import dev.xid.sdk.XidClient;
import dev.xid.sdk.XidClientOptions;
import dev.xid.sdk.XidClaims;
import dev.xid.sdk.XidTokenException;
import dev.xid.sdk.XidJwksException;

XidClient xid = XidClient.create(
    XidClientOptions.builder()
        .issuer("https://xid.dev")
        .audience("your-client-id")
        .webhookSecret("whsec_xxx")
        .build()
);

try {
    XidClaims claims = xid.verifyToken(accessToken);
    String userId = claims.getSub();
    String scope  = claims.getScope();
} catch (XidTokenException e) {
    response.sendError(401, "Unauthorized: " + e.getReason());
} catch (XidJwksException e) {
    response.sendError(503, "Service unavailable");
}

Authenticate an HTTP request

import dev.xid.sdk.AuthResult;

// Bearer-only by default
AuthResult result = xid.authenticateRequest(request.getHeader("Authorization"), null);

if (result.isAuthenticated()) {
    String userId = result.getClaims().get().getSub();
} else {
    response.sendError(401);
}

String token = xid.exchangeSessionToken(
    request.getRequestURL().toString(),
    request.getHeader("Cookie"),
    "/v1/sessions/token"
);

Verify webhook

import dev.xid.sdk.XidWebhookException;

byte[] rawBody = request.getInputStream().readAllBytes();
Map<String, String> headers = Map.of(
    "svix-id",        request.getHeader("svix-id"),
    "svix-timestamp", request.getHeader("svix-timestamp"),
    "svix-signature", request.getHeader("svix-signature")
);

try {
    xid.verifyWebhook(headers, rawBody);
} catch (XidWebhookException e) {
    response.sendError(400, "Invalid webhook: " + e.getReason());
}

XidClientOptions

Method Default Description
.issuer(String) required OIDC issuer; must match token iss exactly
.audience(String) null Expected aud; null skips validation
.webhookSecret(String) null Webhook secret (whsec_ prefix or raw base64)
.jwksCacheDuration(Duration) 1 hour JWKS in-memory cache TTL
.clockSkewTolerance(Duration) 30 seconds exp/nbf clock skew tolerance
.connectTimeout(Duration) 5 seconds HTTP connection timeout for JWKS fetch
.readTimeout(Duration) 10 seconds HTTP read timeout for JWKS fetch

Platform notes

  • Uses nimbus-jose-jwt for JWT/JWKS parsing. ES256 is primary; RS256 and PS256 are supported.
  • All public APIs are synchronous and thread-safe.
  • Logging via SLF4J facade; bring your own implementation (Logback, Log4j2).
  • Exception hierarchy: XidException -> XidTokenException, XidJwksException, XidWebhookException.

Type to search

Use arrow keys to navigateEnter to selectEscape to close