pear-devs/pear-desktop · info
Forbidden
Error message
Forbidden
What it means
'Forbidden' is the HTTP 403 body returned by the auth route's register() handler when the user declines the authorization dialog shown for a new client. The handler shows a dialog (with buttons and defaultId/cancelId of 1); if result.response === 1 (the cancel/decline button), it sets status 403 and returns a null body. This is the deliberate user-rejection path during client pairing, not a bug.
Source
Thrown at src/plugins/api-server/backend/routes/auth.ts:70
if (config.authorizedClients.includes(id)) {
// SKIP CHECK
} else if (config.authStrategy === AuthStrategy.AUTH_AT_FIRST) {
const result = await dialog.showMessageBox({
title: t('plugins.api-server.dialog.request.title'),
message: t('plugins.api-server.dialog.request.message', {
origin: getConnInfo(ctx).remote.address,
ID: id,
}),
buttons: [
t('plugins.api-server.dialog.request.buttons.allow'),
t('plugins.api-server.dialog.request.buttons.deny'),
],
defaultId: 1,
cancelId: 1,
});
if (result.response === 1) {
ctx.status(403);
return ctx.body(null);
}
} else if (config.authStrategy === AuthStrategy.NONE) {
// SKIP CHECK
}
if (!config.authorizedClients.includes(id)) {
setConfig({
authorizedClients: [...config.authorizedClients, id],
});
}
const token = await sign(
{
id,
iat: ~~(Date.now() / 1000),
} satisfies JWTPayload,
config.secret,View on GitHub (pinned to 1e2aac5706)
Solutions
- Retry registration from the client and click 'Allow' in the dialog this time.
- If the client is trusted, pre-add its id to authorizedClients in the config so registration isn't needed.
- If running headless/automated, switch config.authStrategy to AuthStrategy.NONE or pre-authorize clients to avoid interactive prompts.
Defensive patterns
Strategy: fallback
Type guard
const isForbidden = (res: Response): boolean => res.status === 403;
Try / catch
const res = await fetch(registerUrl, opts);
if (res.status === 403) {
// user declined the pairing dialog — inform user; only retry on explicit consent
throw new Error('Pairing declined by user');
} Prevention
- Don't auto-retry registration on 403 — it pops another dialog and annoys the user.
- Pre-authorize known client ids in authorizedClients for unattended setups.
- Use AuthStrategy.NONE only on trusted local networks.
When it happens
Trigger: A client attempts to register/pair via the auth route while authStrategy is not NONE, and the user clicks the 'Cancel'/'Deny' button in the popped-up dialog.
Common situations: User accidentally dismissing the pairing prompt, pairing attempt from an unrecognized machine the user intentionally rejects, or an automation script triggering the dialog while the user is away so it times out to the cancel action.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of pear-devs/pear-desktop@1e2aac5706 (2026-08-27).
Data as JSON: /api/errors/86851725bb5676e4.
Report an issue: GitHub.