Skip to main content

Personal access tokens

A personal access token acts as you from the CLI, your own scripts, or an AI assistant connected through the MCP server. Whatever access you give it, it can never do more than you can.

When to use one​

Use a personal access token when a script or an agent should act as you: your own scripts, your local tools, or an AI assistant. What it does is traceable to you, and it stops working when you lose the access it relies on.

For automation that runs without you, or that shouldn't depend on one person, like a team's CI pipeline, use an API key instead. It belongs to a machine user, so it keeps working when people join or leave the team.

Note: The Copy session token option in your user menu is something else: it copies the short-lived token of your current login, for a quick API call.

What a token can do​

When you create a token, you choose its access:

  • Same access as me: the token follows your access in the organization. Roles you get later are added, and roles you lose stop working for the token right away.
  • Choose grants: the token gets only the resources, roles, or permissions you pick. Each grant works like an API key grant: a resource, plus roles, roles adjusted by hand, or hand-picked permissions.

Either way, every check combines the token's access with yours at that moment. If you lose a role, the tokens that rely on it lose it too, and if your user is deactivated, all your tokens stop working.

You can only grant what you hold yourself: roles you have on that resource or one above it, and permissions you have there.

Using the UI​

Open your user menu (your initials, top right) and select User settings. Walk through the page below:

Save your token securely

The token is displayed only once, right after you generate it. Copy it and store it in a secure location, as it cannot be retrieved later.

To change a token, open its ⋮ menu and click View or edit. You can rename it, change its access and tags, and extend its expiration. Delete removes it for good, and whatever uses it stops working right away.

A token shows Expiring soon in its last 7 days. Once it expires, you can't edit it or extend it anymore, only delete it.

Using the API​

You manage personal access tokens with your own login session, never with an API key: requests authenticated by any API key, a personal access token included, are rejected. To get a session token for these requests, open your user menu and click Copy session token.

The CLI has no commands for personal access tokens, so the examples below use cURL.

Create a token​

Send a POST request to https://api.nullplatform.com/pat. This one creates a token with your own access:

curl -L -X POST 'https://api.nullplatform.com/pat' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{
"name": "local-scripts",
"expires_at": "2027-01-06T00:00:00Z",
"access": "same_as_user",
"tags": [
{ "key": "team", "value": "platform" }
]
}'

Where:

  • expires_at is required. It must be in the future and at most a year away.
  • access is same_as_user for a token that follows your access, or grants (the default) for one limited to the grants you send.

To limit the token instead, send grants with access set to grants. A grant has the same shapes as in an API key: a role, custom actions, or roles adjusted with inherits. This one can only read what's in one account:

{
"name": "read-only-reports",
"expires_at": "2027-01-06T00:00:00Z",
"access": "grants",
"grants": [
{ "nrn": "organization=1:account=2", "role_slug": "member" }
]
}

You'll receive a 201 response like this:

{
"id": 1234,
"name": "local-scripts",
"api_key": "AAAA.1234567890abcdef1234567890abcdefPTs=", // Your new token.
"masked_api_key": "AAAAxxxxxPTs=",
"access": "same_as_user",
"tags": [
{ "key": "team", "value": "platform" }
],
"grants": [
{ "id": 5678, "nrn": "organization=1:account=2", "role_id": 700317756, "role_slug": "developer" }
],
"personal": true,
"owner_id": 42,
"acting_user_id": 42,
"last_used_at": null,
"expires_at": "2027-01-06T00:00:00.000Z",
"expired": false,
"created_at": "2026-10-08T00:00:00.000Z",
"updated_at": "2026-10-08T00:00:00.000Z"
}

Where:

  • api_key is your new token. It's returned only in this response.
  • grants is what the token can do. For a same_as_user token, those are your own grants at this moment.
  • acting_user_id is you: the user the token acts as.
Save your token securely

The token is displayed only once. Make sure to store it in a secure location, as it cannot be retrieved later.

Use the token​

A personal access token works like an API key: exchange it for an access token with a POST request to https://api.nullplatform.com/token. See Generate an access token.

curl -L -X POST 'https://api.nullplatform.com/token' \
-H 'Content-Type: application/json' \
-d '{
"api_key": "AAAA.1234567890abcdef1234567890abcdefPTs="
}'

Tools that take an API key, like the np CLI with --api-key or the MCP server's X-API-Key header, take a personal access token too.

List your tokens​

Send a GET request to https://api.nullplatform.com/pat. You only ever see your own tokens:

curl -L 'https://api.nullplatform.com/pat?search=mcp&status=active,expiring_soon&sort=name:asc' \
-H 'Authorization: Bearer <token>'

These query parameters are all optional:

  • search matches a token's name, or the key or value of one of its tags.
  • status takes one or more of active, expiring_soon (expires within 7 days), and expired, separated by commas.
  • expires_at:range takes two dates, from,to. expires_at:gte and expires_at:lte take one.
  • sort is name:asc, name:desc, last_used_at:asc_nulls_last, or last_used_at:desc_nulls_last.
  • limit (30 by default, 100 at most) and offset page through the results.

Update a token​

Send a PATCH request to https://api.nullplatform.com/pat/<id> with what you want to change: name, tags, access, grants, or expires_at.

curl -L -X PATCH 'https://api.nullplatform.com/pat/1234' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{
"expires_at": "2027-04-06T00:00:00Z"
}'

A few rules apply:

  • expires_at can only move later, up to a year from now. An expired token can't be extended.
  • grants replaces all of the token's grants.
  • Switching to same_as_user drops the token's grants. Switching back to grants requires the grants it should have.

Delete a token​

Send a DELETE request to https://api.nullplatform.com/pat/<id>:

curl -L -X DELETE 'https://api.nullplatform.com/pat/1234' \
-H 'Authorization: Bearer <token>'

You'll receive a 204 response. The token stops working right away, including any access token already issued with it.

Next steps​