RocketChat/Rocket.Chat · error · Error
not-authorized
Error message
not-authorized
What it means
Thrown by fetchIntegration (apps/meteor/server/api/lib/integrations.ts) when the integration exists but hasIntegrationsPermission(userId, integration) returns false. That check passes only if the caller created the integration themselves or holds the incoming/outgoing integration management permissions (including channel-scoped permission for the channels the integration is configured on). It is a plain Error with the message 'not-authorized', so the REST layer returns it as an untyped failure rather than a Meteor permission error code.
Source
Thrown at apps/meteor/server/api/lib/integrations.ts:37
export const findOneIntegration = async ({
userId,
integrationId,
createdBy,
}: {
userId: string;
integrationId: string;
createdBy?: IUser['_id'];
}): Promise<IIntegration> => {
const integration = await Integrations.findOneByIdAndCreatedByIfExists({
_id: integrationId,
createdBy,
});
if (!integration) {
throw new Error('The integration does not exists.');
}
if (!(await hasIntegrationsPermission(userId, integration))) {
throw new Error('not-authorized');
}
return integration;
};
View on GitHub (pinned to b2c16d5842)
Solutions
- Perform the operation with the integration creator's account or an admin token
- Grant the caller's role manage-incoming-integrations / manage-outgoing-integrations (and the channel-scoped add-* permissions where relevant) in Administration > Permissions
- Verify which user ID the auth token maps to — the permission check uses that user, not the body's userId
Example fix
// before: bot token without integration perms
POST /api/v1/integrations.remove { "integrationId": "nS8ML..." } // -> not-authorized
// after: grant role the permission, or use owner/admin credentials
POST /api/v1/integrations.remove (Authorization: owner token) { "integrationId": "nS8ML..." } Defensive patterns
Strategy: try-catch
Try / catch
try {
await client.post('/api/v1/integrations.update', { integrationId, ...changes });
} catch (e: any) {
const msg = e?.response?.data?.error ?? '';
if (msg === 'not-authorized' || e?.response?.status === 403) {
throw new ForbiddenError('caller is not the integration owner and lacks manage-*-integrations permissions');
}
throw e;
} Prevention
- Run integration management jobs with the creator's or an admin's token
- Pre-flight check role permissions (view-full-other-user-info style admin tooling) before bulk operations
- Note the plain 'not-authorized' message — REST returns it without a typed error code
When it happens
Trigger: A non-owner user without manage-incoming-integrations / manage-outgoing-integrations permissions calls integrations.update, integrations.remove, etc. on an integration someone else created; or the caller has the global permission but lacks the channel-level permission for a channel the integration targets.
Common situations: A custom-bot admin role that was never granted the integration permissions; token belonging to a bot user rather than the integration owner; permission sets changed after the integration was created; enterprise workspace restricting integration management to a small group.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/4d9d4e30fe9ec28e.
Report an issue: GitHub.