ZetPinDevelopers

Refreshing & revoking

Access tokens are short-lived. Use the refresh grant to stay authorized, understand rotation and reuse-detection, and revoke tokens when access should end.

Token types

TokenPrefixTTLNotes
Access tokenzpat_1 hour (3600s)Bearer credential for all /dev/v1 calls.
Refresh tokenzprt_30 daysExchanges for a fresh access token. Rotates on every use.
Authorization codezpac_5 minutesSingle-use; exchanged once at the token endpoint.

Only sha256 hashes of tokens, codes, and secrets are ever stored server-side — the raw values exist only in transit and in your storage.

The refresh grant

When the access token nears expiry, exchange the refresh token for a new pair using grant_type=refresh_token. Confidential clients also authenticate with their client_secret.

bash
curl -X POST https://api.zetpin.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=refresh_token \
  -d refresh_token=zprt_1a2b3c4d... \
  -d client_id=zp_app_xxx \
  -d client_secret=zp_sec_xxx
json
{
  "access_token": "zpat_new0token...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "zprt_new0refresh...",
  "scope": "profile.read posts.write posts.read"
}

Rotation & reuse detection

Every refresh returns a new refresh token and invalidates the one you just used. Always persist the new zprt_ from each response and discard the old one.

Reuse revokes everything

Refresh tokens rotate on every use. If an already-used (rotated-out) refresh token is presented again, ZetPin treats it as a replay attack and revokes all of that app + user's grants immediately — the user has to re-authorize. This is why you must store the latest refresh token atomically and never fire two refreshes with the same token concurrently.

Revoking a token

To end access — for example when a user disconnects your integration — POST the token to /oauth/revoke (RFC 7009). You can revoke either an access or a refresh token.

bash
curl -X POST https://api.zetpin.com/oauth/revoke \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d token=zprt_1a2b3c4d... \
  -d client_id=zp_app_xxx \
  -d client_secret=zp_sec_xxx

Revocation responds with 200 OK whether or not the token was still valid — per RFC 7009, revoking an unknown or already-invalid token is not an error.

Storage best practices

  • Store tokens encrypted at rest, server-side where possible. Never expose a client_secret or refresh token to a browser or mobile client.
  • Persist the rotated refresh token from every response before your next request, in a single atomic write, to avoid losing it on a crash.
  • Serialize refreshes per user — concurrent refreshes with the same token trip reuse detection and revoke the grant.
  • Refresh proactively (e.g. shortly before the 1-hour expiry) rather than waiting for a 401 invalid_token.
  • Revoke tokens on user disconnect, logout, or credential rotation.

Related

A revoked or expired access token returns 401 invalid_token with a WWW-Authenticate header — see Errors.