Skip to content

Users & API Keys

Users

Get Current User

GET /api/v1/users/me
Authorization: Bearer <token>

Response:

{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"created_at": "2024-01-15T10:30:00Z"
}

Update Password

PUT /api/v1/users/me/password
Authorization: Bearer <token>
Content-Type: application/json
{
"current_password": "old-password",
"new_password": "new-secure-password"
}

Response:

{
"message": "Password updated successfully"
}

API Keys

List API Keys

GET /api/v1/api-keys
Authorization: Bearer <token>

Response:

[
{
"id": "660e8400-e29b-41d4-a716-446655440000",
"name": "MacBook Pro",
"key_prefix": "exp_k1_7f8a9b",
"created_at": "2024-01-15T10:30:00Z",
"last_used_at": "2024-01-20T14:00:00Z"
},
{
"id": "770e8400-e29b-41d4-a716-446655440000",
"name": "CI Pipeline",
"key_prefix": "exp_k1_3c4d5e",
"created_at": "2024-01-10T08:00:00Z",
"last_used_at": null
}
]

Create API Key

POST /api/v1/api-keys
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "My New Key"
}

Response:

{
"api_key": {
"id": "880e8400-e29b-41d4-a716-446655440000",
"name": "My New Key",
"key_prefix": "exp_k1_9a8b7c",
"created_at": "2024-01-25T10:00:00Z",
"last_used_at": null
},
"key": "exp_k1_9a8b7c6d5e4f3a2b1c0d..."
}

Delete API Key

DELETE /api/v1/api-keys/{id}
Authorization: Bearer <token>

Response:

HTTP/1.1 204 No Content

API Key Format

API keys follow this format:

exp_k1_<random_bytes>
  • exp — Expose prefix
  • k1 — Key version 1
  • <random_bytes> — Cryptographically random identifier

Usage Tracking

The last_used_at field updates when an API key is used for:

  • Tunnel authentication
  • API requests

This helps identify unused keys for cleanup.

Error Responses

Key Not Found

HTTP/1.1 404 Not Found
{
"error": "not_found",
"message": "API key not found"
}

Invalid Password

HTTP/1.1 400 Bad Request
{
"error": "invalid_password",
"message": "Current password is incorrect"
}

Password Requirements

New passwords must:

  • Be at least 8 characters
  • Not match the current password
HTTP/1.1 400 Bad Request
{
"error": "validation_error",
"message": "Password must be at least 8 characters"
}