| Layer | Token type | Used for |
|---|---|---|
| User JWT | Bearer <jwt> |
Account management, credits, tokens, subscription — /api/auth/*, /api/v2/users/* |
| API Token | Bearer |
Watermark encode/decode calls — /api/watermark/*, MCP server |
1. User Authentication (JWT)
User JWTs are short-lived access tokens issued on login. They authenticate calls to account management endpoints. You don't need to handle this manually if you use the dashboard — it manages tokens in the browser automatically.
Registration & email verification
# 1. Register
curl -X POST https://textwatermarking.com/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "yourpassword"}'
# → Check your inbox for a verification link, then click it (or hit the URL directly):
# GET https://textwatermarking.com/api/auth/verify-email?token=<token>
Login
curl -X POST https://textwatermarking.com/api/auth/login \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{"email": "[email protected]", "password": "yourpassword"}'
# Response:
# {
# "accessToken": "eyJhbGci...", ← valid for 2 hours
# "user": { "id": "...", "plan": "pro", ... }
# }
# A httpOnly refresh token cookie is also set automatically.
Using the access token
curl https://textwatermarking.com/api/v2/users/me \
-H "Authorization: Bearer eyJhbGci..."
Refreshing the access token
When the access token expires (after 2 hours), use the refresh token cookie to get a new one — no re-login required.
curl -X POST https://textwatermarking.com/api/auth/refresh \
-b cookies.txt \
-c cookies.txt
# Response: { "accessToken": "eyJhbGci..." } ← fresh 2-hour token
Logout
curl -X POST https://textwatermarking.com/api/auth/logout \
-b cookies.txt \
-H "Authorization: Bearer eyJhbGci..."
# Revokes the refresh token. The access token expires naturally after 2h.
2. API Token Authentication
API tokens authenticate watermark calls. They are long-lived, scoped by permission (encode / decode), and optionally linked to a signing channel for keyed watermarking.
Creating an API token
Create tokens from your dashboard or via API (requires a valid user JWT):
curl -X POST https://textwatermarking.com/api/v2/tokens \
-H "Authorization: Bearer <user-jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "My encode bot",
"permissions": ["encode"],
"signing_channel_id": null
}'
# Response:
# {
# "token": "a3f8e2b1c9d47f6a2b5c8d1e9f3a4b7c...", ← shown ONCE, store it securely
# "id": "...",
# "name": "My encode bot",
# "token_prefix": "mcp_a3f8e2b1"
# }
Important: The full token value is shown only once at creation time. Store it in an environment variable immediately — it cannot be retrieved again. If lost, revoke and create a new one.
Using an API token
curl -X POST https://textwatermarking.com/api/watermark/encode \
-H "Authorization: Bearer a3f8e2b1c9d47f6a..." \
-H "Content-Type: application/json" \
-d '{
"text": "The quick brown fox jumps over the lazy dog",
"secret": "owner-id-42"
}'
Token permissions
| Permission | Allowed endpoints | Typical use case |
|---|---|---|
encode |
/encode, /encode-robust |
Content creation pipeline, LLM agent inserting watermarks |
decode |
/decode, /decode-robust |
Verification pipeline, plagiarism detection bot |
encode + decode |
All watermark endpoints | MCP server, general-purpose integration |
MCP server usage
The published MCP server uses an API token directly — no JWT required:
# In your MCP config (e.g. Claude Desktop)
{
"mcpServers": {
"textwatermarking": {
"command": "npx",
"args": ["@textwatermarking/mcp-server", "--token", "a3f8e2b1c9d47f6a..."]
}
}
}
Revoking a token
curl -X DELETE https://textwatermarking.com/api/v2/users/tokens/<token-id> \
-H "Authorization: Bearer <user-jwt>"
3. Security Best Practices
- Store API tokens in environment variables — never hardcode them in source code or commit them to git.
- Use the minimum required permission — give encode-only tokens to pipelines that only write watermarks; separate decode tokens for verification.
- Revoke compromised tokens immediately — from your dashboard or via
DELETE /api/v2/users/tokens/:id. Revocation is instant. - Never expose tokens client-side — proxy all watermark calls through your own backend if you need to call from a browser.
- Use signing channels for sensitive content — keyed watermarks can only be decoded through your channel, adding an ownership verification layer.
4. Authentication Errors
| Status | Meaning | Fix |
|---|---|---|
401 |
Missing, invalid, or expired token | Check the Authorization header; refresh JWT if expired |
403 |
Token valid but insufficient permissions, or account suspended | Use a token with the correct permission (encode/decode); contact support if suspended |
402 |
Valid token but no credits remaining | Top up credits or upgrade plan; response includes a checkout_url |
See the Error Handling page for the full list of error codes and response shapes.