Skip to main content
The PunchPlay Platform API supports two app-bound auth patterns:
  • Authorization code + PKCE for browser, website, and native apps that can receive a callback
  • Device code for TV, desktop, CLI, and clients without a convenient browser callback
Both flows issue scoped bearer tokens for /api/platform/v1.

Register your app first

Create a developer app at Get API key. Each app receives a stable client_id.
  • Confidential clients also receive a client_secret
  • Public clients use client_id only
  • Every app defines its maximum allowed_scopes
  • The approval screen shows the app name and requested scopes before the user approves access

Client types

Current scopes

Apps can currently request these scopes: If a request omits scope, PunchPlay grants the app’s configured allowed_scopes. If a request asks for a scope outside the app’s allowed_scopes, the request fails with invalid_scope. email:read is reserved and is not available to developer apps. Use the stable user ID returned by GET /api/platform/v1/me when linking accounts. PunchPlay’s /me/push-devices routes are also reserved for developer apps explicitly marked as first-party. The notification scopes remain available to third-party apps for inbox, unread-state, and preference features. Third-party apps should only redirect users to the GET /api/platform/v1/oauth/authorize endpoint. The consent screen’s POST decision handler is used by PunchPlay’s own signed-in, same-origin UI; it is not an app approval API, even though it appears in the generated reference with security: [].

Flow selection

Use this rule:
  • Use authorization code + PKCE for browser, website, and native apps that can redirect a user and receive a callback
  • Use device code for TV, desktop, CLI, and clients that cannot handle a normal browser callback cleanly

Authorization code + PKCE

1. Redirect the user to PunchPlay

Required query parameters:
  • response_type=code
  • client_id=YOUR_CLIENT_ID
  • redirect_uri=YOUR_REGISTERED_REDIRECT_URI
  • code_challenge=BASE64URL_SHA256_OF_CODE_VERIFIER
  • code_challenge_method=S256
Optional:
  • scope=profile:read playback:read playback:write events:read
  • state=YOUR_OPAQUE_STATE
Example:
PunchPlay authenticates the user if needed, shows the consent screen, then redirects with HTTP 302 back to your redirect_uri with:
  • code
  • state if you sent one
  • scope
If the request cannot be completed, PunchPlay redirects back with an error. Redirect-based failures may also include request_id so the developer has something concrete to report. Users can review and revoke approved apps later from https://punchplay.tv/settings/connected-apps. Store the state value with the pending authorization transaction and compare it exactly on callback. Keep the original PKCE verifier private until the code exchange completes; a verifier is not a substitute for state validation.

2. Exchange the code for tokens

Public apps send client_id only. Confidential apps send both client_id and client_secret. Successful response:

3. Refresh the access token

Successful refresh returns a rotated refresh token. Replace the old one immediately.

Device code

1. Request a device code

Public clients omit client_secret. Response fields:

2. Poll the token endpoint

Pending approval returns HTTP 400 with the standard OAuth device-flow error:
Success returns:

3. Refresh the access token

Successful refresh returns a rotated refresh token. Replace the old one immediately.

Authenticated requests

Use the access token in the Authorization header:
Platform tokens are scoped to the platform namespace and intended for endpoints under /api/platform/v1.

Token lifetimes

Access tokens live for one hour (expires_in: 3600). Refresh tokens live for a year, and rotate on every use — each refresh returns a new one, and the previous one stops working immediately. Your client must refresh. Either refresh shortly before expires_in elapses, or retry once on a 401 after refreshing. Both work; do not do neither.
Serialise your refreshes. Because refresh tokens rotate, two refreshes running in parallel will invalidate each other and sign the user out. If several requests can hit 401 at once, funnel them through a single refresh.The in-repository @punchplay/api-client handles this for you — pass onUnauthorized and it refreshes, retries once, and collapses concurrent failures into one refresh. The package is not currently published to the public npm registry; use the local or tarball instructions in its README.
Access tokens are deliberately short lived because they are bearer credentials: anyone holding one is the user until it expires. Revocation covers leaks you notice; a short lifetime covers the ones you do not.

Debugging auth failures

Platform auth errors include:
  • request_id in the JSON body
  • X-PunchPlay-Request-Id in the response headers
PunchPlay also persists platform request logs keyed by request_id. When reporting a failure, capture:
  • request_id
  • UTC timestamp
  • endpoint path
  • client_id
  • status code
  • raw error body
For developer questions, use the PunchPlay Discord and include the request ID. Never post access tokens, refresh tokens, or client secrets.

Security guidance

  • Treat client_secret, refresh tokens, and access tokens as sensitive credentials.
  • Do not embed client_secret in native apps, browser apps, or sample code intended for public distribution.
  • Use public clients when your app cannot safely hold a secret.
  • Keep allowed_scopes as narrow as possible for each app.
  • Rotate secrets immediately if you suspect they were exposed.
  • Deactivate an app if you need to revoke its issued tokens quickly.
  • If your app runs entirely in the browser, keep in mind that standard EventSource clients cannot attach custom authorization headers.
Poll every few seconds until the user approves the request or the device code expires. Back off if your app has multiple concurrent authorization attempts. Authentication JSON and form bodies are limited to 64 KiB and must arrive within 10 seconds. Oversized bodies return 413; timed-out bodies return 408.

Check the authenticated identity

After obtaining a token, verify who you are acting as: