RocketChat/Rocket.Chat · error · Meteor.Error
not_authorized
not_authorized
Error message
not_authorized
What it means
addOutgoingIntegration (creating an outgoing webhook integration) throws bare not_authorized when there is no userId on the connection, or when the caller holds neither 'manage-outgoing-integrations' nor 'manage-own-outgoing-integrations' — either single permission is sufficient. The check runs after check() validation of the payload and before validateOutgoingIntegration.
Source
Thrown at apps/meteor/server/meteor-methods/integrations/outgoing/addOutgoingIntegration.ts:55
triggerWords: Match.Maybe([String]),
avatar: Match.Maybe(String),
token: Match.Maybe(String),
impersonateUser: Match.Maybe(Boolean),
retryCount: Match.Maybe(Number),
retryDelay: Match.Maybe(String),
retryFailedCalls: Match.Maybe(Boolean),
runOnEdits: Match.Maybe(Boolean),
targetRoom: Match.Maybe(String),
triggerWordAnywhere: Match.Maybe(Boolean),
}),
);
if (
!userId ||
(!(await hasPermissionAsync(userId, 'manage-outgoing-integrations')) &&
!(await hasPermissionAsync(userId, 'manage-own-outgoing-integrations')))
) {
throw new Meteor.Error('not_authorized');
}
if (integration.script?.trim()) {
validateScriptEngine(integration.scriptEngine ?? 'isolated-vm');
}
const integrationData = await validateOutgoingIntegration(integration, userId);
const { insertedId } = await Integrations.insertOne(removeEmpty(integrationData));
const integrationStored = await Integrations.findOne({ _id: insertedId });
if (!integrationStored) {
throw new Error('Error inserting integration');
}
void notifyOnIntegrationChanged({ ...integrationStored, _id: insertedId }, 'inserted');
View on GitHub (pinned to b2c16d5842)
Solutions
- Authenticate the client before invoking the method
- Grant 'manage-own-outgoing-integrations' (self-service) or 'manage-outgoing-integrations' (full admin) to the caller's role in Administration > Permissions
- Have the user log out and back in (or refresh) so permission changes take effect
- Use POST /v1/integrations.create with an authorized user's token instead of DDP
Example fix
// before: button always visible, call fails for unprivileged users
await Meteor.callAsync('addOutgoingIntegration', integration);
// after: gate the UI on permission
const canAdd = usePermission('manage-outgoing-integrations') || usePermission('manage-own-outgoing-integrations');
{canAdd && <AddOutgoingIntegrationButton />} Defensive patterns
Strategy: validation
Validate before calling
// client
const canAdd =
usePermission('manage-outgoing-integrations') ||
usePermission('manage-own-outgoing-integrations');
// server
const canAdd =
!!userId &&
((await hasPermissionAsync(userId, 'manage-outgoing-integrations')) ||
(await hasPermissionAsync(userId, 'manage-own-outgoing-integrations'))); Try / catch
try {
await Meteor.callAsync('addOutgoingIntegration', integration);
} catch (err) {
if (err instanceof Meteor.Error && err.error === 'not_authorized') {
// request login or the integration permission, then stop
return;
}
throw err;
} Prevention
- Gate integration-creation UI behind the two manage permissions
- For self-service webhooks, grant manage-own-outgoing-integrations to the intended role
- Refresh sessions after granting permissions — stale sessions keep failing
When it happens
Trigger: Logged-out client calling addOutgoingIntegration, or a logged-in user whose roles lack both integration permissions; also when the workspace has integrations enabled but the admin never granted manage-own-outgoing-integrations to regular roles.
Common situations: Non-admin users attempting self-service outgoing webhook creation on hardened workspaces; custom scripts invoking the DDP method without login; role changes not yet reflected because the session is stale.
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
- not_authorized
- error-user-lacks-message-impersonate-permission
- not_authorized
- not-authorized
- error-invalid-role
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/d7baea5e81dc66ba.
Report an issue: GitHub.