| Situation | Flow |
|---|---|
| Web app with a redirect URL | Callback mode=user (fragment) or mode=server (panel POSTs JSON) |
| CLI / TV / headless — no redirect URL | Device — user enters a short code; client polls |
Full guide (RAG): api/oauth2.md · Login SSO is different: auth/oidc-sso.md
/dashboard/account/oauth2/api/new?...params....mode=user: panel redirects user to callbackurl with result in URL fragment (#...).mode=server: panel calls callbackurl server-to-server with JSON credentials, then shows success in panel UI.authorization_code via POST /api/user/api-clients/oauth2/token.mode=device on the callback URL — use the device endpoints below.| Name | Required | Description |
|---|---|---|
name | Yes | API key/client name that will be created on approval. |
callbackurl | Yes | Absolute callback URL. Supports https://, localhost http://, and custom app schemes like client:// or myapp://. |
allowedips | No | Comma/newline separated IPv4/IPv6/CIDR restrictions. |
alertCors | No | true to enable foreign IP blocked-attempt notifications (only with allowedips). |
appName | No | Display name of requesting app. |
appLogo | No | Absolute URL of app logo. |
description | No | Consent description text shown to the user. |
mode | No | user (default) for browser redirect, or server for server-to-server callback delivery. |
Generate, validate, and open consent URLs for mode=user / mode=server.
Not validated yet.
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.
callbackurl#public_key=fp_...&private_key=fp_...&token_type=featherpanel_api_key&issued_at=...&authorization_code=fpoauthcode_...
callbackurl#error=access_denied&error_description=The resource owner denied the request
{"success":true,"token_type":"featherpanel_api_key","public_key":"fp_...","private_key":"fp_...","authorization_code":"fpoauthcode_...","issued_at":"..."}
POST /api/user/api-clients/oauth2/token
Content-Type: application/json
{"code":"fpoauthcode_..."}
GET /api/user/api-clients/oauth2/metadata?...params... while user is logged in./dashboard/account/oauth2/api/new?...params....GET /api/user/api-clients/oauth2/metadata?name=My+Integration&callbackurl=client%3A%2F%2Foauth%2Fcallback&mode=user
public_key and private_key and success === true for server mode.POST /api/user/api-clients/validate using returned public_key.authorization_code through POST /api/user/api-clients/oauth2/token.POST /api/user/api-clients/validate
Content-Type: application/json
{"public_key":"fp_..."}
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);