Demonstrates SciChart's Simple Server Validation v2 flow — server-side license validation using only HMAC-SHA256, with no native library and no JNI. The entire server-side change is a single @RestController using javax.crypto.Mac from the JDK.
A v2 token can take one of two shapes on the wire:
- Inline (4 fields) —
v2:serverNonce:serverNow:hmac. Independent of any client state; servable to many clients and embeddable in HTML via a<meta>tag. Should still be signed per request — the embeddedserverNowages relative to the client's clock and will fall outsidemax_skewonce the token is older than the licence's tolerance, so caching past that point causes valid clients to reject otherwise-correct tokens. - Round-trip (5 fields) —
v2:clientNonce:serverNonce:serverNow:hmac. The client generates a random nonce in WASM and sends it as?nonce=<hex>; the server echoes it into the signed token. A captured response is bound to the requesting client and cannot be replayed on another origin.
For most deployments the two shapes are interchangeable under a single licence — mix inline meta-tag delivery and round-trip requests freely, the SciChart client accepts whichever arrives. Deployments that can't keep server and client clocks in reasonable alignment should be locked to round-trip only: inline tokens can drift stale, round-trip tokens are signed against the request that produced them.
The fourth field of SV:H:V:N chooses: 0 (permissive default) accepts both shapes; 1 (restricted) accepts round-trip only and disables inline delivery.
This example's server handles both shapes from one endpoint; the licence on the client side decides what it accepts.
Browser (SciChart.js)
→ GET /api/license?orderid=<X>[&nonce=<hex>] (nonce only when validate_nonce=1)
← 200 OK body: v2:[clientNonce:]serverNonce:serverNow:hmac
SciChart WASM verifies HMAC, checks clock skew against the licence's
max_skew, enforces server-time monotonicity across re-validations,
and caches the result in a cookie until valid_time has elapsed.
SciChartSurface.create()boots the WASM, which reads theSV:H:V:Nfeature from the runtime licence key.- The WASM checks the
scLicensecookie. Still valid → it stops here and no request is made. - Otherwise, in round-trip mode it generates a client nonce, then calls
GET /api/license?orderid=<X>[&nonce=<hex>]. - The server signs a fresh token and returns it. It keeps no state, doesn't read the cookie, and ignores
orderid— a multi-licence deployment would useorderidto pick which secret to sign with. - The WASM verifies the HMAC, the clock skew against
max_skew, thatserverNowhasn't moved backwards since the last validation, and (round-trip) that its own nonce came back unchanged. - On success it writes
scLicense— licence key, accepted token, expiry, validation time — and renders without a watermark.
The server only issues tokens; every check happens client-side and the result never comes back. A successful issue is not proof the client accepted it, so treat the browser console as the real verdict. Because of step 2 you will not see a request on every page load — once cached, the client stays quiet until valid_time elapses.
-
JDK 17+
-
Spring Boot 3 (pulled in by Maven, nothing to install)
-
Maven 3.9+
-
Node.js 18+ (for building the client bundle)
-
A SciChart license with the
SV:H:V:Nfeature flag, where:max_skew— accepted client/server clock skew asHorH.MM(e.g.0.05= 5 min,1= 1 h,1.30= 90 min).0disables the check.valid_time— token validity in the client's wall clock, sameH.MMformat (e.g.168= 7 days,0.30= 30 min)validate_nonce—0accepts either shape (permissive default);1restricts to round-trip only (inline delivery disabled)
Contact support@scichart.com to have an SV v2 feature added to your license.
On macOS, install the JDK and Maven with Homebrew, then link the JDK so the system java picks it up:
brew install openjdk@17 maven
sudo ln -sfn /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk \
/Library/Java/JavaVirtualMachines/openjdk-17.jdkCheck with java -version (should report 17 or later) and mvn -v.
-
Get your Server Secret Log in to SciChart MyAccount and open Orders & Keys → Manage Licenses → Runtime License Key. Copy the Server Secret (a 64-char hex string) from the Server Secret section. Only present if your license carries the Simple Server Validation (
SV) feature. -
Set the Server Secret Edit
src/main/java/com/example/scichart/LicenseController.javaand replaceSCICHART_SERVER_SECRETwith your Server Secret. In production, prefer externalising this viaapplication.properties:scichart.server-secret=<your 64-char hex Server Secret>Then inject it with
@Value("${scichart.server-secret}"). -
Set the client license key Edit
client/index.tsand replace the key passed tosetRuntimeLicenseKeywith your full license key string. The key must carry anSV:H:V:Nfeature. -
Build the client bundle
npm install npm run build
This writes
bundle.jsand the SciChart WASM files intosrc/main/resources/static/, where Spring Boot serves them automatically. -
Run the server
mvn spring-boot:run
Open http://localhost:8080 — the chart should render without a watermark. The port is set by
server.portinsrc/main/resources/application.properties; override it per run withmvn spring-boot:run -Dspring-boot.run.arguments=--server.port=9090.Or package a standalone jar and run that:
mvn clean package java -jar target/scichart-spring-simple-server-licensing-1.0.0.jar
Stop the server with
Ctrl+C. Re-runnpm run buildafter any change toclient/index.ts; changes to the Java sources need a restart.
- Open browser DevTools → Network. Look for
GET /api/license?orderid=...returning200. When the licence has validate_nonce=1 the URL also has&nonce=<hex>. - In Application → Cookies, you should see
scLicenseset with a future expiry. - The console should log
Simple server license validated. - The server logs a line per issued token, e.g.
License token issued (inline) to 0:0:0:0:0:0:0:1: serverNonce=... serverNow=....
A successful run: the chart renders without a watermark and GET /api/license?orderid=ABT-TEAM-Bundle returns 200 OK. The 95-byte response is an inline token — v2: + 16-char serverNonce + 10-digit serverNow + 64-char hmac + 2 separators — and the absence of &nonce= in the URL means this licence has validate_nonce=0.
Use a private/incognito window, as shown, or clear the scLicense cookie first. On a normal reload the cached cookie suppresses the request entirely and you'll see neither the network call nor the server log.
Inline shape (4 colon-separated fields):
v2:<serverNonce>:<serverNow>:<hmac>
Round-trip shape (5 colon-separated fields):
v2:<clientNonce>:<serverNonce>:<serverNow>:<hmac>
serverNonce— server-generated random hex (≥ 16 chars)serverNow— server wall-clock Unix timestamp, decimal secondsclientNonce(round-trip only) — verbatim echo of the request's?nonce=valuehmac—HMAC-SHA256(serverSecret, payload)where the payload is everything before the final colon
See ../SimpleServerSideLicensing-Readme.md for Python, Go, Ruby, PHP, and Rust snippets.
Key point in all cases:
HexFormat.of().parseHex()decodes the Server Secret to binary bytes before it is passed to HMAC. Do not use the hex string directly as the key.
Inline-mode caching: not recommended. Inline tokens are not bound to a particular client, but the embedded
serverNowages relative to the client's clock and will fall outsidemax_skewonce the cache is older than the licence's tolerance — sign per request. Round-trip responses cannot be cached either.
