Skip to content
This repository was archived by the owner on Jun 1, 2026. It is now read-only.

Commit 12aeef4

Browse files
committed
docs: clarify device auth compatibility
1 parent 08cd1e6 commit 12aeef4

2 files changed

Lines changed: 30 additions & 21 deletions

File tree

docs/DEVICE_AUTHENTICATION.md

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,68 +2,72 @@
22

33
## Overview
44

5-
All `/v2/devices/*` endpoints require authentication via Ed25519 request signing. The server supports two authentication methods: **Gem** (recommended) and **individual headers** (legacy).
5+
All `/v2/devices/*` endpoints require Ed25519 request signing. New clients should use the Gem `Authorization` header. Individual `x-device-*` headers remain supported for existing clients and should be treated as legacy compatibility.
66

7-
## Method 1: Gem Authorization Header (Recommended)
7+
## Gem Authorization Header
88

99
```
1010
Authorization: Gem base64(<device_id_hex>.<timestamp_ms>.<wallet_id>.<body_hash_hex>.<signature_hex>)
1111
```
1212

13-
The payload is always 5 dot-separated parts. After base64-decoding:
13+
The decoded payload is always 5 dot-separated parts:
1414
- `device_id_hex` - 64-character hex Ed25519 public key
1515
- `timestamp_ms` - Unix timestamp in milliseconds
16-
- `wallet_id` - Wallet identifier (empty string for non-wallet endpoints)
17-
- `body_hash_hex` - 64-character hex SHA256 hash of request body
16+
- `wallet_id` - wallet identifier, or an empty string for non-wallet endpoints
17+
- `body_hash_hex` - 64-character hex SHA256 hash of the request body
1818
- `signature_hex` - 128-character hex Ed25519 signature
1919

20-
When `wallet_id` is empty, the payload contains `..` (two consecutive dots).
20+
When `wallet_id` is empty, the payload contains `..` between timestamp and body hash.
2121

2222
**Signed message:**
23+
2324
```
2425
{timestamp}.{method}.{path}.{walletId}.{bodyHash}
2526
```
2627

27-
`walletId` is empty for non-wallet endpoints, producing `..` in the message:
28+
Examples:
2829

2930
```
3031
1706000000000.GET./v2/devices..e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
3132
1706000000000.GET./v2/devices/assets.multicoin_0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb.e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
3233
```
3334

34-
## Method 2: Individual Headers (Legacy)
35+
## Legacy Individual Headers
3536

36-
**Required:**
37-
- `x-device-id`: Unique device identifier (64-character hex Ed25519 public key)
38-
- `x-device-signature`: Ed25519 signature (hex or base64)
39-
- `x-device-timestamp`: Unix timestamp in milliseconds
40-
- `x-device-body-hash`: SHA256 hash of request body (hex)
37+
The server still accepts individual headers for compatibility:
4138

42-
**Optional (wallet-specific endpoints):**
43-
- `x-wallet-id`: Wallet identifier (format: `multicoin_{address}`)
39+
- `x-device-id`: 64-character hex Ed25519 public key
40+
- `x-device-signature`: Ed25519 signature, hex or base64
41+
- `x-device-timestamp`: Unix timestamp in milliseconds
42+
- `x-device-body-hash`: 64-character hex SHA256 hash of the request body
43+
- `x-wallet-id`: wallet identifier for wallet-scoped endpoints
4444

4545
**Signed message:**
46+
4647
```
4748
v1.{timestamp}.{method}.{path}.{bodyHash}
4849
```
4950

50-
Note: `walletId` is **not** included in the legacy signed message.
51+
The legacy signed message does not include `walletId`; new clients should not add new dependencies on this format.
5152

5253
## Request Examples
5354

54-
### Gem (wallet-scoped)
55+
### Gem Wallet-scoped Endpoint
56+
5557
```http
5658
GET /v2/devices/assets?from_timestamp=1234567890
5759
Authorization: Gem base64(abc123...def456.1706000000000.multicoin_0x742d...f0bEb.e3b0c44...b855.aabb11...)
5860
```
5961

60-
### Gem (no wallet)
62+
### Gem Non-wallet Endpoint
63+
6164
```http
6265
GET /v2/devices
6366
Authorization: Gem base64(abc123...def456.1706000000000..e3b0c44...b855.aabb11...)
6467
```
6568

66-
### Individual Headers (legacy)
69+
### Legacy Individual Headers
70+
6771
```http
6872
GET /v2/devices/assets?from_timestamp=1234567890
6973
x-device-id: abc123...def456
@@ -77,5 +81,5 @@ x-device-body-hash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852
7781

7882
- Request signature verification: [`apps/api/src/devices/signature.rs`](../apps/api/src/devices/signature.rs)
7983
- Cryptographic verification: [`crates/gem_auth/src/device_signature.rs`](../crates/gem_auth/src/device_signature.rs)
80-
- Request guards: [`apps/api/src/devices/guard.rs`](../apps/api/src/devices/guard.rs)
84+
- Request guards: [`apps/api/src/devices/guard/`](../apps/api/src/devices/guard/)
8185
- Error handling: [`apps/api/src/devices/error.rs`](../apps/api/src/devices/error.rs)

docs/WALLET_AUTHENTICATION.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,13 @@ Wallet authentication endpoints require proof of wallet ownership via blockchain
2929
}
3030
```
3131

32-
**Required Headers:**
32+
Wallet-authenticated requests are still device-authenticated requests. Use the Gem `Authorization` header for device authentication where possible; existing clients may still use the legacy individual headers documented in [Device Authentication](DEVICE_AUTHENTICATION.md).
33+
34+
For the current `WalletSigned<T>` guard, include:
3335
- `x-device-body-hash`: SHA256 hash of request body (hex)
3436

37+
This binds the wallet-signed JSON body to the request body read by the guard. Moving this check fully into the Gem `Authorization` payload should be done with the legacy-removal PR.
38+
3539
## Nonce Request
3640

3741
**Endpoint:**
@@ -72,6 +76,7 @@ GET /v2/devices/auth/nonce
7276
```
7377
POST https://api.gemwallet.com/v2/devices/rewards/referrals/create
7478
Content-Type: application/json
79+
Authorization: Gem base64(<device_id_hex>.<timestamp_ms>.<wallet_id>.<body_hash_hex>.<signature_hex>)
7580
x-device-body-hash: a1b2c3d4e5f6...
7681
7782
{

0 commit comments

Comments
 (0)