Skip to content

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.

  1. Device announces itself -> Server issues an access token (24h expiration)

  2. Client uses access token for API calls

  3. Token approaches expiration -> Client refreshes token

  4. Repeat 1-3 until device explicitly deregisters

All tokens are tied to device announcements. When a device announcement expires, associated tokens become invalid.

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.

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 current token expires in < 30 minutes (recommended)

  • After receiving HTTP 401 responses

  • Before performing critical operations

POST /v1/auth/refresh
POST /v1/auth/refresh HTTP/1.1
Content-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)
{
"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": "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.

{
"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).

{
"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.

If a token is compromised:

  1. The attacker can send/receive messages as the device until token expires

  2. Attacker cannot refresh the token without the device’s private key (will get error 4001: INVALID_SIGNATURE)

  3. Token automatically becomes invalid after 24 hours

  4. 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.