RocketChat/Rocket.Chat · error · Meteor.Error

not_authorized

not_authorized

Error message

Unauthorized

What it means

addIncomingIntegration rejects with not_authorized when there is no userId OR the user holds neither `manage-incoming-integrations` nor `manage-own-incoming-integrations`. Creating incoming webhooks requires at least one of these two permissions; the check runs after the integration object passes its Match validation.

Source

Thrown at apps/meteor/server/meteor-methods/integrations/incoming/addIncomingIntegration.ts:48

			enabled: Boolean,
			username: String,
			channel: String,
			alias: Match.Maybe(String),
			emoji: Match.Maybe(String),
			scriptEnabled: Boolean,
			scriptEngine: Match.Maybe(String),
			overrideDestinationChannelEnabled: Match.Maybe(Boolean),
			script: Match.Maybe(String),
			avatar: Match.Maybe(String),
		}),
	);

	if (
		!userId ||
		(!(await hasPermissionAsync(userId, 'manage-incoming-integrations')) &&
			!(await hasPermissionAsync(userId, 'manage-own-incoming-integrations')))
	) {
		throw new Meteor.Error('not_authorized', 'Unauthorized', {
			method: 'addIncomingIntegration',
		});
	}

	if (!integration.channel || typeof integration.channel.valueOf() !== 'string') {
		throw new Meteor.Error('error-invalid-channel', 'Invalid channel', {
			method: 'addIncomingIntegration',
		});
	}

	if (integration.channel.trim() === '') {
		throw new Meteor.Error('error-invalid-channel', 'Invalid channel', {
			method: 'addIncomingIntegration',
		});
	}

	const channels = integration.channel.split(',').map((channel) => channel.trim());

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Grant `manage-incoming-integrations` (full control) or `manage-own-incoming-integrations` (own webhooks only) to the caller's role
  2. Verify authentication first — the same error covers a missing userId
  3. For REST use POST /v1/integrations.create with a token whose role carries one of these permissions

Example fix

// before
Meteor.call('addIncomingIntegration', integration, cb); // not_authorized

// after
const canManage = usePermission('manage-incoming-integrations') || usePermission('manage-own-incoming-integrations');
if (canManage) Meteor.call('addIncomingIntegration', integration, cb);
Defensive patterns

Strategy: validation

Validate before calling

const canManage =
  usePermission('manage-incoming-integrations') || usePermission('manage-own-incoming-integrations');
if (Meteor.userId() && canManage) {
  Meteor.call('addIncomingIntegration', integration, cb);
}

Try / catch

Meteor.call('addIncomingIntegration', integration, (err) => {
  if (err && (err as Meteor.Error).error === 'not_authorized') {
    // either not logged in or missing BOTH manage-incoming-integrations and
    // manage-own-incoming-integrations — check session first, then permissions
  }
});

Prevention

When it happens

Trigger: Calling `Meteor.call('addIncomingIntegration', integration)` while logged out, or as a user whose roles include neither integration permission — e.g. a regular member or a bot account without the integration role.

Common situations: Allowing non-admins to create their own webhooks without granting manage-own-incoming-integrations; custom roles built by copying 'user' instead of a privileged template; scripts assuming admin rights on a restricted token.

Understand the failure class

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/89e4d6123d5213c3. Report an issue: GitHub.