pingd docs

Users & tokens

Roles

RoleWhat they can do
adminManage users, topics, permissions, devices, tokens.
userOwn topics, devices, tokens. Subscribe to topics they can read.
guestSystem-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:

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.

MethodPathWho
GET/users/:username/tokensSelf or admin
POST/users/:username/tokensSelf or admin (guests denied)
DELETE/tokens/:idOwner 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)

MethodPathNotes
GET/usersAdmin only
POST/usersAdmin only; cannot create guest
GET/users/:usernameAdmin or self
PATCH/users/:usernameAdmin or self (some fields admin-only)
DELETE/users/:usernameAdmin 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:

HeaderValueUsed for
AuthorizationBearer <token>Identifying a user/account
X-Topic-Tokentk_...Capped access to one topic without granting account permissions