Mint an end-user Portal JWT

​

Mints a signed Portal user JWT for one of your end users. Send the token to your client; it then connects to the realtime edge and calls client routes with Authorization: Bearer <jwt>.

claims is an opaque bag you define — it travels with the token and is available to your channel config's authorization logic and to message senders (as read-only metadata). channels, when present, restricts the token to the listed channels and grants; omit it to allow whatever the channel config permits. ttl accepts values like 1h, 30m, 45s, 2d, or a bare number of seconds; it defaults to one hour.

Server-only. A request carrying an Origin header (a browser) is rejected.

Body·

required
application/json
  • Your end user's id. Becomes the JWT sub.

  • A map of channel id to a list of granted capabilities (for example ["connect", "publish"]). Omit on a token to allow whatever the channel config permits.

    Properties: 1
  • Opaque claims bag; travels with the token and is visible to your config's authorization logic.

    Properties: 1
  • Token lifetime. Accepts 1h, 30m, 45s, 2d, or a bare number of seconds. Defaults to one hour.

Responses

  • application/json
  • application/json
  • application/json
  • application/json
Request Example for post/v1/tokens
curl https://api.useportal.co/v1/tokens \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --data '{
  "userId": "u_123",
  "claims": {
    "username": "ada",
    "avatar": "https://cdn.example.com/ada.png"
  },
  "ttl": "1h"
}'
A signed JWT and its expiry
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImVudl8xMjMifQ.eyJzdWIiOiJ1XzEyMyIsImFub24iOmZhbHNlLCJpYXQiOjE3NTI5MTIwMDAsImV4cCI6MTc1MjkxNTYwMH0.signature",
  "expiresAt": "2026-07-19T03:00:00.000Z"
}