arcane_init is the ownership check. Call it once at launch with your portal public key. You do not add a second ownership step unless you need a custom flow.
The game does not talk to the network for this: the Arcane desktop launcher refreshes tickets online; the SDK only reads and verifies the local cache.
Portal public key
The string you pass to init is the public key generated for your title in the Arcane portal. In the current crate API the parameter is still namedgame_id — pass the portal public key there. The same value keys local flag and ticket files, and must match the ticket gid claim.
Default init policy
arcane_init(public_key):
- Reads
flags/{public_key}.jsonfordrm_enabled - If
drm_enabledisfalse→ returnsOwnershipStatus::DrmDisabled(no ticket required) - Otherwise (flag
trueor missing) → runs the offline ownership check
Offline check (what init runs when DRM is on)
When DRM is not disabled, init verifies the cached ticket:- Loads a ticket file for the public key (scans
tickets/{user_id}/) - Rejects clock rollback vs
last_seen_wall_time - If
drm_enabledon the ticket file is false →DrmDisabled - Ensures the ticket string is non-empty
- Compares cached
device_hashto the local fingerprint - Verifies the JWT (ES256, issuer
arcane-drm, audiencearcane-game-sdk)
Data layout
drm_data_root() resolves {app_data} via the OS application data directory.
Ticket claims
Device fingerprint
machine_id is a UUID written once under the DRM root (mode 0600 on Unix). device_hash is the first 16 bytes of SHA-256(machine_id), hex-encoded. Tickets are bound to that hash so they cannot be copied to another machine.
JWKS
Verification keys come fromjwks.json. The JWT kid selects the key when present. If JWKS is missing, the SDK returns ticket_invalid — refresh via the desktop app.
Custom check only
check_ownership_offline always runs the ticket path (useful if you manage DRM policy yourself). Prefer arcane_init for normal launch.