sdkey
Official Ruby client for SDKey license authentication.
Implements the sealed session protocol: Ed25519-verified handshake, HKDF session keys, and AES-256-GCM validate envelopes, plus plaintext client auth (register / login / upgrade). See PROTOCOL.md.
Version: 0.2.0 (RubyGems / git tag v0.2.0)
Install
gem install sdkey
Or in a Gemfile:
gem "sdkey", "~> 0.2.0"
Requires Ruby 3.1+ with OpenSSL (Ed25519, AES-GCM, HKDF).
Quick start
Embed these values from the SDKey dashboard when you ship your app. app_version must exactly match the application version configured on the server (clientVersion); mismatch returns APP_OUTDATED.
require "sdkey"
client = Sdkey::Client.new(
api_base_url: "https://api.sdkey.dev",
app_id: "YOUR_APP_ID",
app_version: "1.0.0",
app_public_key_b64: "YOUR_APP_PUBLIC_KEY_BASE64"
)
begin
# hwid is optional (omit for web clients — server skips HWID checks)
result = client.validate("SDKY-XXXX-XXXX-XXXX-XXXX", "machine-hwid")
if result.success
puts "licensed #{result.status} #{result.expires_at} tier=#{result.subscription_tier}"
puts "message #{result.}"
else
puts "denied #{result.code} #{result.}"
end
rescue Sdkey::Error => err
# Init / transport failures use `error` text from the server when present
puts "#{err.code} #{err.}"
raise
end
validate calls init automatically when no session exists. Sessions last ~15 minutes server-side; on SESSION_EXPIRED the client clears local state so the next call re-handshakes.
Client auth (plaintext JSON)
reg = client.register(
username: "player1",
password: "••••••••",
license_key: "SDKY-XXXX-XXXX-XXXX-XXXX",
hwid: "machine-hwid" # optional
)
if reg.success
puts [reg.session_token, reg.user, reg.license].inspect
else
puts "#{reg.code} #{reg.error}"
end
login = client.login(username: "player1", password: "••••••••")
upgrade = client.upgrade(username: "player1", license_key: "SDKY-HIGHER-TIER-KEY")
upgrade takes username + license key only (no password). The new key’s subscriptionTier must be strictly greater than the user’s current tier.
Where message vs error appears
Per-app responseMessages may customize many strings. The SDK surfaces whatever the server returns.
| Surface | Success text field | Failure text field |
|---|---|---|
| Session init | (none) | error (raised as Sdkey::Error#message) |
| Sealed validate | message |
message |
| Client register / login / upgrade | (none) | error on ClientAuthResult |
Example JSON shapes
Init failure (plaintext):
{ "success": false, "error": "Client version outdated", "code": "APP_OUTDATED" }
Sealed validate success (message):
{
"success": true,
"code": "OK",
"message": "validated",
"status": "active",
"expiresAt": "2026-01-01T00:00:00.000Z",
"subscriptionTier": 0,
"sessionId": "...",
"timestamp": 1720000001,
"v": 1
}
Sealed validate failure (still message, not error):
{
"success": false,
"code": "HWID_MISMATCH",
"message": "Hardware ID mismatch",
"status": null,
"expiresAt": null,
"sessionId": "...",
"timestamp": 1720000001,
"v": 1
}
Client auth failure (error):
{
"success": false,
"error": "License tier must be higher than the current tier",
"code": "TIER_NOT_HIGHER"
}
API
Sdkey::Client.new(...)
| Option | Type | Description |
|---|---|---|
api_base_url |
String |
API origin (no trailing slash) |
app_id |
String |
Application UUID |
app_version |
String |
Exact app version → sent as clientVersion |
app_public_key_b64 |
String |
Raw Ed25519 public key (32 bytes), base64 |
http_post |
callable | Optional HTTP POST override (tests / custom transport) |
Methods
init— challenge handshake; verifies the signed hello; derives the AES session key; sendsclientVersionvalidate(license_key, hwid = nil)— sealed validate; omitshwidJSON key when not provided; always decrypts then verifies the Ed25519 signature before trustingsuccessregister(...)/login(...)/upgrade(...)— plaintextPOST /api/v1/client/*session/clear_session— inspect or drop the local session
Errors
Protocol / transport failures raise Sdkey::Error with a code and message (server error text when the API provides one):
INIT_FAILED · APP_OUTDATED · HELLO_SIGNATURE_INVALID · VALIDATE_RESPONSE_INVALID · RESPONSE_SIGNATURE_INVALID · SESSION_MISMATCH · CLOCK_SKEW · NETWORK
License denials (banned, HWID mismatch, etc.) return a normal ValidateResult with success: false — they are not raised. Auth denials return ClientAuthResult with success: false, code, and error.
This package does not include developer tooling / Bearer (sdk_live_…) management APIs.
Security notes
- Never ship app private keys in a client.
- Do not skip signature verification — that is the anti-spoof binding.
- This package is open source; the SDKey server remains a separate product.
Development
bundle install
bundle exec rake test
Repository: https://github.com/SDKeyDev/sdkey-ruby
License
MIT