Skip to content

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 Vonvon instance) has not been performed yet and must be completed before production use.

Registry status: UNPUBLISHED. Install this SDK only from the repository source checkout; do not use an external package registry.

Request authentication is Bearer-only by default. An application-owned JWT cookie is read only when its exact name is configured. The opaque __Host-vonvon.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.vonvon</groupId>
  <artifactId>vonvon-sdk-java</artifactId>
  <version>0.1.0-alpha.0</version>
</dependency>

Quick start

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

import dev.vonvon.sdk.VonvonClient;
import dev.vonvon.sdk.VonvonClientOptions;
import dev.vonvon.sdk.VonvonClaims;
import dev.vonvon.sdk.VonvonTokenException;
import dev.vonvon.sdk.VonvonJwksException;

VonvonClient vonvon = VonvonClient.create(
    VonvonClientOptions.builder()
        .issuer("https://vonvon.id")
        .audience("your-client-id")
        .webhookSecret("whsec_xxx")
        .build()
);

try {
    VonvonClaims claims = vonvon.verifyToken(accessToken);
    String userId = claims.getSub();
    String scope  = claims.getScope();
} catch (VonvonTokenException e) {
    response.sendError(401, "Unauthorized: " + e.getReason());
} catch (VonvonJwksException e) {
    response.sendError(503, "Service unavailable");
}

Authenticate an HTTP request

import dev.vonvon.sdk.AuthResult;

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

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

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

Verify webhook

import dev.vonvon.sdk.VonvonWebhookException;

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 {
    vonvon.verifyWebhook(headers, rawBody);
} catch (VonvonWebhookException e) {
    response.sendError(400, "Invalid webhook: " + e.getReason());
}

VonvonClientOptions

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: VonvonException -> VonvonTokenException, VonvonJwksException, VonvonWebhookException.
Navigation

Type to search...

Use arrow keys to navigateEnter to selectEscape to close