Does a Portainer API key expire, and what is the safest way to test integrations without production credentials?
0 reputation · 10 Sept 2020, 07:58 UTC
0 reputation · 10 Sept 2020, 07:58 UTC
I want to exercise Portainer's integration flows (endpoint listing, registry connections, stack deployment) in an isolated test instance without ever touching production secrets. My plan is a fresh portainer-ce container with its own data volume, a throwaway registry configured with dummy credentials via the built-in "Test connection" button, and a limited-scope API key used from a small script.
The part I cannot pin down is the lifecycle of that API key. The UI lets me create one, but the documentation I have read is unclear on whether keys have a default expiration, whether expiry can be configured per key, and what an expired key returns to an API client (HTTP status and error shape). This matters because my test pipeline needs to detect credential failure distinctly from a genuine integration failure.
Assuming a recent Portainer CE release (2.x), my questions are:
/api/endpoints return once a key has expired or been revoked, so my script can distinguish it from other 401/403 causes?35775 reputation · 10 Sept 2020, 09:06 UTC
Portainer CE access tokens (API keys) historically did not expire by default — they stayed valid until revoked. Some recent 2.x releases added an optional expiration at creation time, but this is version-sensitive, so check your exact release rather than assuming either behavior. An expired or revoked token returns HTTP 401 with a generic JSON error body that does not reliably distinguish "expired" from "revoked" from "malformed." And no, there is no documented fully ephemeral validate-only auth endpoint — the registry "Test connection" button validates credentials, but the registry entry itself is persisted.
Confirmed behavior across Portainer CE 2.x:
POST /api/users/{id}/tokens). The raw value is shown once; only a digest is stored.Version-sensitive (verify on your instance): whether the creation dialog offers an expiration field and what the default TTL is. Check your version via GET /api/status or the UI footer, then create a token and see if an expiry option appears. If it does, set the shortest TTL in your test instance so your pipeline actually exercises the expiry path.
Design your script around a simple rule, because the API won't give you more granularity:
Verify the exact shape on your instance:
curl -s -o /dev/null -w "%{http_code}\n" \
-H "X-API-Key: ptr_xxxx" \
http://localhost:9000/api/endpoints
# revoke the token in the UI, then repeat and record status + bodyIf your version supports expiry, set the minimum TTL, wait, and compare the response to the revoked case. Expect them to look identical; if they do, your pipeline should log "credential rejected" rather than a specific cause.
Your plan is sound, with two additions:
For the registry: "Test connection" validates dummy credentials without any pull or deployment, and it should fail cleanly with fake values. But the registry entry is stored in Portainer's database, so if "persist nothing" is a hard requirement, delete the registry entry via the API after the test, or destroy the whole data volume — which, since your instance is disposable, is the simplest guarantee.
Expiry defaults and the exact error JSON have changed across 2.x releases and are flagged here for verification against your deployed version rather than asserted. The 401/403 split and the per-user token model are stable behavior you can build against.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.