← Back to API Reference

OAuth2 API Consent: Documentation + Playground

Approved requests issue credentials with full account API access. Only approve trusted apps and secure your callback receiver.

Which flow?

SituationFlow
Web app with a redirect URLCallback mode=user (fragment) or mode=server (panel POSTs JSON)
CLI / TV / headless — no redirect URLDevice — user enters a short code; client polls

Full guide (RAG): api/oauth2.md · Login SSO is different: auth/oidc-sso.md

Callback flow overview

  1. Build authorize URL to /dashboard/account/oauth2/api/new?...params....
  2. User reviews request and approves/denies consent.
  3. mode=user: panel redirects user to callbackurl with result in URL fragment (#...).
  4. mode=server: panel calls callbackurl server-to-server with JSON credentials, then shows success in panel UI.
  5. Optional: app exchanges one-time authorization_code via POST /api/user/api-clients/oauth2/token.
  6. Do not pass mode=device on the callback URL — use the device endpoints below.

Query Parameters

NameRequiredDescription
nameYesAPI key/client name that will be created on approval.
callbackurlYesAbsolute callback URL. Supports https://, localhost http://, and custom app schemes like client:// or myapp://.
allowedipsNoComma/newline separated IPv4/IPv6/CIDR restrictions.
alertCorsNotrue to enable foreign IP blocked-attempt notifications (only with allowedips).
appNameNoDisplay name of requesting app.
appLogoNoAbsolute URL of app logo.
descriptionNoConsent description text shown to the user.
modeNouser (default) for browser redirect, or server for server-to-server callback delivery.

Playground — callback (with redirect URL)

Generate, validate, and open consent URLs for mode=user / mode=server.


    
Not validated yet.

Playground — device (no redirect URL)

RFC 8628-style. Start a device grant, show the user the verification URI + code, then poll until keys arrive. Live calls need a running panel (same origin).

User page: /dashboard/account/oauth2/api/device · Endpoints: POST …/oauth2/device then POST …/oauth2/device/token

Not started.

Callback Fragment Contract

Approve

callbackurl#public_key=fp_...&private_key=fp_...&token_type=featherpanel_api_key&issued_at=...&authorization_code=fpoauthcode_...

Deny

callbackurl#error=access_denied&error_description=The resource owner denied the request

Server Mode Callback Body

{"success":true,"token_type":"featherpanel_api_key","public_key":"fp_...","private_key":"fp_...","authorization_code":"fpoauthcode_...","issued_at":"..."}

Token Exchange

POST /api/user/api-clients/oauth2/token
Content-Type: application/json

{"code":"fpoauthcode_..."}

Validation Guide (Client + Server)

Client-side validation (before opening consent)

  1. Build your query string on the app side.
  2. Call GET /api/user/api-clients/oauth2/metadata?...params... while user is logged in.
  3. If response is success, open /dashboard/account/oauth2/api/new?...params....
GET /api/user/api-clients/oauth2/metadata?name=My+Integration&callbackurl=client%3A%2F%2Foauth%2Fcallback&mode=user

Server-side validation (after callback)

  1. Check payload has public_key and private_key and success === true for server mode.
  2. Validate issued credentials via POST /api/user/api-clients/validate using returned public_key.
  3. Optionally exchange/verify authorization_code through POST /api/user/api-clients/oauth2/token.
POST /api/user/api-clients/validate
Content-Type: application/json

{"public_key":"fp_..."}

Callback Parser Snippet (App Side)

function parseOAuthFragment(hash) {
  const fragment = (hash || window.location.hash || '').replace(/^#/, '');
  const params = new URLSearchParams(fragment);
  return {
    publicKey: params.get('public_key'),
    privateKey: params.get('private_key'),
    error: params.get('error'),
    errorDescription: params.get('error_description'),
    authorizationCode: params.get('authorization_code'),
  };
}

const result = parseOAuthFragment();
history.replaceState(null, '', location.pathname + location.search);