links.arjun.tv/docs/end-user/jwt-vs-pat-when-to-use

JWT vs PAT: When to Use Each

Use this guide when you need a clear answer to: "Should this call use JWT or PAT?"

Quick answer

If your workflow is...UseWhy
Interactive control-plane work (dashboard, admin/operator scripts)JWTJWT is the auth model for /v2/handles/*, /v2/account/domains/*, /v2/billing/*, and admin/operator surfaces
Server-to-server automation on one handlePATPAT is handle-scoped, scope-limited, and built for automation on PAT-capable routes
PAT lifecycle management (create/list/revoke tokens)JWTPAT management endpoints themselves require signed-in handle access (OPERATOR+)

JWT vs PAT comparison

DimensionJWTPAT
IdentitySigned-in user sessionHandle-scoped API credential
Typical headerAuthorization: Bearer <jwt>Authorization: Bearer patv1_<tokenId>.<secret> or x-api-key
Scope modelRole-based (CREATOR, OPERATOR, OWNER, platform admin)Explicit scopes (links.read, webhooks.write, etc.)
Primary route familyControl plane (/v2/handles/*, /v2/account/domains/*, /v2/billing/*)PAT-capable automation surfaces (primarily /v2/public/handles/{handle}/*)
ReachAll handles user can accessOne handle per token
Session lifecycleLogin/refresh/logout flowCreate once, rotate/revoke intentionally

Route boundary rules

Note

  • Use JWT for control-plane and account/admin operations.
  • Use PAT for automation routes that explicitly support PAT scopes.
  • A PAT is not a universal replacement for JWT.

JWT-first examples

  • POST /v2/handles/{handle}/tokens (create PAT)
  • PUT /v2/handles/{handle}/collaborators
  • POST /v2/billing/checkout-session
  • POST /v2/account/domains

PAT-first examples

  • GET /v2/public/handles/{handle}/links
  • PUT /v2/public/handles/{handle}/links/{slug}
  • GET /v2/public/handles/{handle}/analytics
  • POST /v2/public/handles/{handle}/webhooks

Important exceptions

Most PAT usage is on /v2/public/handles/{handle}/*, but selected handle-scoped agent/QA endpoints also allow PAT when documented with PAT scopes. Treat PAT support as endpoint-specific, not automatic.

Use API Endpoint Coverage Map to confirm auth mode for a specific route.

How JWT session refresh works

JWT login returns token payload fields and sets an HttpOnly refresh cookie. Refresh uses that cookie via POST /v2/auth/refresh.

Implementation detail: the refresh cookie key is _10x_admin_refresh and the session cookie is managed as HttpOnly; Secure; SameSite=Lax.

Browser pattern

const refreshed = await fetch("https://api.10x.in/v2/auth/refresh", {
  method: "POST",
  headers: { "content-type": "application/json" },
  credentials: "include"
});

cURL pattern (cookie jar)

# 1) Login and save cookies (includes refresh cookie)
curl -sS -c cookies.txt -X POST "https://api.10x.in/v2/auth/login" \
  -H "content-type: application/json" \
  -d '{"email":"owner@example.com","password":"<password>"}'

# 2) Refresh using saved refresh cookie
curl -sS -b cookies.txt -c cookies.txt -X POST "https://api.10x.in/v2/auth/refresh" \
  -H "content-type: application/json"

If the refresh cookie is missing or invalid, expect 401 refresh_token_missing or 401 invalid_refresh_token.

How PAT lifecycle works

PATs are created via JWT-authenticated control-plane routes, then used for automation calls.

Implementation detail: when both x-api-key and Authorization are present, PAT parsing prioritizes x-api-key.

Bootstrap PAT with JWT

curl -sS -X POST "https://api.10x.in/v2/handles/${HANDLE}/tokens" \
  -H "authorization: Bearer ${JWT_TOKEN}" \
  -H "content-type: application/json" \
  -d '{
    "name": "ci-links",
    "scopes": ["links.read","links.write","analytics.read"],
    "expiresInDays": 30
  }'

Use PAT in automation

curl -sS "https://api.10x.in/v2/public/handles/${HANDLE}/links" \
  -H "x-api-key: ${PAT_TOKEN}"

PAT auth guardrails are rate-limited per minute both by (handle + tokenId + source IP) and by handle burst limits.

Error behavior when token type is wrong

SituationTypical outcomeMeaning
JWT expired401 token_expiredRe-authenticate / refresh session
PAT expired401 token_expiredRotate or recreate PAT
PAT revoked401 token_revokedToken was invalidated
JWT sent to PAT-only endpoint401 invalid_token_format or auth failureEndpoint expects PAT format/scope flow
PAT sent to JWT-only endpoint403 insufficient_scope or JWT-required auth errorEndpoint requires signed-in user session
PAT missing required scope403 insufficient_scopeToken exists but does not grant needed permission

Recommended usage patterns

  1. Use JWT to bootstrap control-plane setup

    Sign in, create/update handle resources, and mint scoped PATs.

  2. Use PAT for unattended jobs

    Run CI/CD, scheduled tasks, webhook workers, and backend integrations with least-privilege scopes.

  3. Rotate PATs deliberately

    Use one PAT per system, rotate regularly, and revoke old tokens immediately after cutover.

  4. Do not put JWTs in long-running automation

    JWTs are session-oriented and expire; use PATs for durable service credentials.

Copy-paste decision checklist

  1. Does this endpoint live under control-plane families (/v2/handles/*, /v2/account/domains/*, /v2/billing/*, admin/operator)? Use JWT.
  2. Is this an automation endpoint that explicitly supports PAT scopes? Use PAT.
  3. Need cross-handle user context? Use JWT.
  4. Need one handle + least privilege + unattended execution? Use PAT.
  5. Not sure? Check API Endpoint Coverage Map first.

Related