Authentication API
Cryptid uses JWT (JSON Web Token) Bearer authentication for all API endpoints after initial device registration. Unlike traditional systems, there are no usernames or passwords; Authentication is entirely cryptographic, based on Ed25519 device keys.
Token Lifecycle
Section titled “Token Lifecycle”-
Device announces itself -> Server issues an access token (24h expiration)
-
Client uses access token for API calls
-
Token approaches expiration -> Client refreshes token
-
Repeat 1-3 until device explicitly deregisters
All tokens are tied to device announcements. When a device announcement expires, associated tokens become invalid.
Authentication Header
Section titled “Authentication Header”All authenticated endpoints require a JWT Bearer token in the Authorization header:
Authorization: Bearer {access_token}
Token Source:
Access tokens are obtained from:
-
Initial device registration POST /v1/announce
-
Token refresh POST /v1/auth/refresh
Token Scope:
Each token is bound to a single device address and cannot be used by other devices. Tokens are not transferable.
Refresh Token
Section titled “Refresh Token”Obtains a new access token before the current one expires. This allows long-running devices to maintain continuous API access without re-announcing (which would reset the delivery mapping).
When to Refresh
Section titled “When to Refresh”-
When current token expires in < 30 minutes (recommended)
-
After receiving HTTP 401 responses
-
Before performing critical operations
Endpoint
Section titled “Endpoint”POST /v1/auth/refresh
Request
Section titled “Request”POST /v1/auth/refresh HTTP/1.1Content-Type: application/json
{ "refresh_token": "jwt_refresh_token", "device_signature": "ed25519_signature_over_refresh_token"}
Parameters:
-
refresh_token
: The JWT refresh token (obtained from initial announcement or previous refresh) -
device_signature
: Ed25519 signature over the refresh token using device’s private key
Signature Generation:
signature = ed25519_sign(device_private_key, refresh_token)
Response (200 OK)
Section titled “Response (200 OK)”{ "access_token": "new_jwt_access_token", "expires_at": 1758999500}
Response Fields:
-
access_token
: New JWT access token for API authentication -
expires_at
: Unix timestamp when this token expires (typically 24 hours from issuance)
Error Responses
Section titled “Error Responses”401 Unauthorized
Section titled “401 Unauthorized”{ "error": "INVALID_REFRESH_TOKEN", "message": "Refresh token is invalid or expired", "code": 4008}
Causes:
-
Refresh token expired (device announcement expired)
-
Invalid signature (device key doesn’t match)
-
Malformed refresh token
-
Device announcement was removed or expired
Solution:
Re-announce the device with POST /v1/announce
to obtain new tokens.
400 Bad Request
Section titled “400 Bad Request”{ "error": "INVALID_SIGNATURE", "message": "Ed25519 signature verification failed", "code": 4001}
Causes:
-
device_signature
doesn’t match the device’s public key -
Signature was generated over incorrect data
-
Wrong private key used for signing
Solution:
Ensure signature is generated as ed25519_sign(device_private_key, refresh_token)
.
429 Too Many Requests
Section titled “429 Too Many Requests”{ "error": "RATE_LIMIT_EXCEEDED", "message": "Too many requests", "code": 4004, "retry_after": 60}
Causes:
-
Too many refresh attempts in short period
-
Respect the
retry_after
header value (seconds)
Solution:
Implement exponential backoff for retries.
Token Compromise
Section titled “Token Compromise”If a token is compromised:
-
The attacker can send/receive messages as the device until token expires
-
Attacker cannot refresh the token without the device’s private key (will get error
4001: INVALID_SIGNATURE
) -
Token automatically becomes invalid after 24 hours
-
Device owner can forcibly invalidate by re-announcing or deregistering
Protection: Even if access_token and refresh_token are both stolen, the attacker cannot extend access beyond token expiration without possessing the device’s Ed25519 private key.