Users & tokens
Roles
| Role | What they can do |
|---|---|
admin | Manage users, topics, permissions, devices, tokens. |
user | Own topics, devices, tokens. Subscribe to topics they can read. |
guest | System-created low-privilege account for anonymous installs. Cannot create topics or extra tokens. |
The guest role is system-only. Admin endpoints can't create or assign it.
Anonymous access
Anonymous means no bearer token. Anonymous callers can only use public topic access
(publicRead / publicPublish) or a topic share token.
They cannot create devices, manage subscriptions, or call user/account endpoints.
Authentication
Bearer tokens go in the Authorization header:
Authorization: Bearer <token>
Login
curl -s http://localhost:7685/auth/login \
-H 'Content-Type: application/json' \
-d '{
"username": "vi",
"password": "password1",
"label": "web"
}'
import requests
requests.post(
"http://localhost:7685/auth/login",
json={
"username": "vi",
"password": "password1",
"label": "web",
},
)
Returns:
{
"token": "bearer-token",
"userID": "uuid",
"username": "vi"
}
If a token with the same label already exists for the user and is still valid,
login reuses it. Otherwise it creates a new one. label is just a hint;
"web", "iphone", "ci", whatever helps you tell tokens apart.
Registration
Public registration is off by default. Enable it with:
PINGD_ALLOW_REGISTRATION=true
Then:
curl -s http://localhost:7685/auth/register \
-H 'Content-Type: application/json' \
-d '{
"username": "vi",
"password": "password1",
"label": "web"
}'
import requests
requests.post(
"http://localhost:7685/auth/register",
json={
"username": "vi",
"password": "password1",
"label": "web",
},
)
Registration creates a normal user account. Admins can also create users via POST /users.
Guest sessions
curl -s -X POST http://localhost:7685/auth/guest
import requests
requests.post("http://localhost:7685/auth/guest")
Creates a system-generated user (guest-xxxxxx) and a non-expiring bearer token.
Use this for anonymous app/device installs that still need authenticated endpoints. Guests can:
- register devices
- subscribe their devices to topics they can read
- read topics with
publicRead=true - publish topics with
publicPublish=true - read or publish with a valid share token
Guests cannot create topics or create extra bearer tokens. User/global permission grants do not affect guests.
Current user
curl -s http://localhost:7685/me \
-H 'Authorization: Bearer $TOKEN'
import requests
requests.get(
"http://localhost:7685/me",
headers={"Authorization": "Bearer TOKEN"},
)
Returns the authenticated user's profile.
Logout
curl -s -X DELETE http://localhost:7685/auth/logout \
-H 'Authorization: Bearer $TOKEN'
import requests
requests.delete(
"http://localhost:7685/auth/logout",
headers={"Authorization": "Bearer TOKEN"},
)
Revokes the active token. To also deactivate a push device on logout, send the device's push token:
curl -s -X DELETE http://localhost:7685/auth/logout \
-H 'Authorization: Bearer $TOKEN' \
-H 'X-Push-Token: <push-token>'
import requests
requests.delete(
"http://localhost:7685/auth/logout",
headers={
"Authorization": "Bearer TOKEN",
"X-Push-Token": "<push-token>",
},
)
The device is only deactivated if it belongs to the calling user.
API tokens
Mint long-lived tokens for scripts, CI, and integrations.
| Method | Path | Who |
|---|---|---|
| GET | /users/:username/tokens | Self or admin |
| POST | /users/:username/tokens | Self or admin (guests denied) |
| DELETE | /tokens/:id | Owner or admin |
Create a token
curl -s http://localhost:7685/users/vi/tokens \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"label": "automation",
"expiresAt": "2026-12-31T23:59:59Z"
}'
pingd-cli tokens create \
--username vi \
--label automation \
--expires-in 30d
import requests
requests.post(
"http://localhost:7685/users/vi/tokens",
headers={"Authorization": "Bearer TOKEN"},
json={
"label": "automation",
"expiresAt": "2026-12-31T23:59:59Z",
},
)
Omit expiresAt for a non-expiring token. The plaintext
token is returned once.
Token visibility
Admins see full token values when listing tokens. Non-admin users see masked values for previously created tokens (the plaintext is only available at creation time).
User management (admin)
| Method | Path | Notes |
|---|---|---|
| GET | /users | Admin only |
| POST | /users | Admin only; cannot create guest |
| GET | /users/:username | Admin or self |
| PATCH | /users/:username | Admin or self (some fields admin-only) |
| DELETE | /users/:username | Admin only; cannot remove last admin |
Create a user
curl -s http://localhost:7685/users \
-H 'Authorization: Bearer $ADMIN_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"username": "vi",
"password": "password1",
"role": "user"
}'
pingd-cli users create \
--username vi \
--password password1 \
--role user
import requests
requests.post(
"http://localhost:7685/users",
headers={"Authorization": "Bearer ADMIN_TOKEN"},
json={
"username": "vi",
"password": "password1",
"role": "user",
},
)
Bearer token vs share token
Two unrelated credentials. You can use either, both, or neither, depending on the topic:
| Header | Value | Used for |
|---|---|---|
Authorization | Bearer <token> | Identifying a user/account |
X-Topic-Token | tk_... | Capped access to one topic without granting account permissions |