Authentication¶
The Tether API supports two authentication methods:
- JWT access tokens (issued by passwordless auth)
- API keys (long-lived management tokens)
Passwordless Auth¶
Tether uses magic code authentication — no passwords.
Request a Code¶
A magic code is sent to the provided email.
Exchange Code for Tokens (manual entry flow)¶
POST /auth/verify-code
Content-Type: application/json
{
"email": "you@example.com",
"code": "123456"
}
Response:
Exchange One-Time Magic Link Token¶
When users click the magic link from email, clients can exchange the opaque token directly (without exposing email/code in the URL):
Response:
Refresh Token (body mode)¶
Response:
Browser Cookie Session Mode (recommended for web apps)¶
For browser clients, use cookie mode so refresh tokens are never readable by JavaScript:
- Send header
X-Tether-Session-Mode: cookieon: POST /auth/verify-codePOST /auth/exchange-codePOST /auth/refreshPOST /auth/logout- Include credentials in browser requests.
- API sets
tether_refresh_tokenas an httpOnly cookie. - In cookie mode,
refreshTokenin JSON responses is blank (use cookie rotation instead).
Cookie-mode refresh call:
Note
Refresh tokens are rotated on each use — the old token is invalidated and a new pair is returned. Always store and use the new refreshToken from the response (or updated cookie in cookie mode).
Using Access Tokens¶
Include the access token in the Authorization header:
Get Current User¶
Response:
List Active Sessions¶
Lists active refresh-token sessions for the currently authenticated user.
Response:
{
"sessions": [
{
"tokenId": "f7d9...",
"userAgent": "Mozilla/5.0 ...",
"ipAddress": "203.0.113.10",
"createdAt": 1736899200000,
"lastUsedAt": 1736899800000,
"expiresAt": 1739500000000
}
]
}
Note
/sessions accepts access JWTs (not API keys).
Logout¶
Body mode:
Cookie mode:
Invalidates the current refresh-token session.
API Keys¶
API keys are long-lived tokens for programmatic access. Use them to manage agents from CI/CD pipelines, scripts, or backend services without going through the magic code flow.
API keys use the sk-tether-name- prefix for easy identification and leak detection.
Create an API Key¶
Requires JWT authentication.
POST /api-keys
Authorization: Bearer eyJ...
Content-Type: application/json
{
"name": "CI Pipeline",
"expiresInDays": 90
}
Response:
{
"id": "key_abc123",
"key": "sk-tether-name-...",
"name": "CI Pipeline",
"keyPrefix": "sk-tether-name-abc",
"expiresAt": 1748304000000,
"createdAt": 1740528000000
}
Note
Timestamps are Unix epoch milliseconds. expiresAt is 0 if the key doesn't expire.
Warning
The full key value is shown only once. Store it securely — the API stores only a hash.
List API Keys¶
Response:
[
{
"id": "key_abc123",
"name": "CI Pipeline",
"keyPrefix": "sk-tether-name-abc",
"expiresAt": 1748304000000,
"createdAt": 1740528000000,
"lastUsedAt": 1740571200000,
"revoked": false
}
]
Revoke an API Key¶
Using API Keys¶
Include the API key in the Authorization header, just like a JWT:
API keys can be used with most agent endpoints (/agents/*) and domain endpoints (/domains/*). Creating and managing API keys themselves requires JWT authentication.
Note
Key lifecycle endpoints (GET /agents/{id}/keys, POST /agents/{id}/keys/rotate, POST /agents/{id}/keys/{keyId}/revoke) accept bearer auth (JWT or API key). Rotation/revocation require step-up verification (stepUpCode or challenge + proof).
For automation with API keys, prefer challenge + proof step-up.
Limits¶
| Limit | Value |
|---|---|
| API keys per account | 10 |
| Rate limit | 10 requests/minute |
Info
If you need more API keys, please contact us at support@tether.name.
Security Notes¶
- API keys are hashed before storage — they cannot be retrieved after creation.
- The
sk-tether-name-prefix enables automated leak detection in logs and repositories. - Revoked keys are rejected immediately.
- Set
expiresInDaysto limit key lifetime. Omit for non-expiring keys.
Public Endpoints¶
The following endpoints do not require authentication:
GET /— Health checkPOST /challenge— Request a challengePOST /challenge/verify— Submit proofGET /challenge/{code}— Check challenge statusGET /AGENTS.md— Agent-readable verification guidanceGET /.well-known/tether-name.json— Machine-readable endpoint map and protocol metadataGET /version— Build metadataGET /stats— Global verification stats