RocketChat/Rocket.Chat · error · Meteor.Error

not_authorized

not_authorized

Error message

Unauthorized

What it means

The exported helper deleteOutgoingIntegration(integrationId, userId) throws not_authorized 'Unauthorized' as its first guard when the passed userId is falsy. Server-side callers (REST endpoints, other methods) supply userId explicitly, so a falsy value means the calling layer never resolved an authenticated user.

Source

Thrown at apps/meteor/server/meteor-methods/integrations/outgoing/deleteOutgoingIntegration.ts:18

import type { ServerMethods } from '@rocket.chat/ddp-client';
import { Integrations, IntegrationHistory } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../../lib/authorization/hasPermission';
import { methodDeprecationLogger } from '../../../lib/deprecationWarningLogger';
import { notifyOnIntegrationChanged } from '../../../lib/notifyListener';

declare module '@rocket.chat/ddp-client' {
	// eslint-disable-next-line @typescript-eslint/naming-convention
	interface ServerMethods {
		deleteOutgoingIntegration(integrationId: string): Promise<boolean>;
	}
}

export const deleteOutgoingIntegration = async (integrationId: string, userId: string): Promise<void> => {
	if (!userId) {
		throw new Meteor.Error('not_authorized', 'Unauthorized', {
			method: 'deleteOutgoingIntegration',
		});
	}

	const canManageAllIntegrations = await hasPermissionAsync(userId, 'manage-outgoing-integrations');
	const canManageOwnIntegrations = !canManageAllIntegrations && (await hasPermissionAsync(userId, 'manage-own-outgoing-integrations'));

	if (!canManageAllIntegrations && !canManageOwnIntegrations) {
		throw new Meteor.Error('not_authorized', 'Unauthorized', {
			method: 'deleteOutgoingIntegration',
		});
	}

	const integration = await Integrations.removeByIdAndCreatedByIfExists({
		_id: integrationId,
		...(canManageOwnIntegrations && { createdBy: userId }),
	});

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Resolve and assert an authenticated userId before invoking the helper
  2. Prefer the shipped method wrapper or POST /v1/integrations.remove, which perform auth themselves
  3. Throw early with a clear error when Meteor.userId() returns null instead of forwarding it

Example fix

// before
await deleteOutgoingIntegration(integrationId, Meteor.userId() ?? '');

// after
const uid = Meteor.userId();
if (!uid) {
  throw new Meteor.Error('not_authorized', 'Unauthorized');
}
await deleteOutgoingIntegration(integrationId, uid);
Defensive patterns

Strategy: validation

Validate before calling

const uid = Meteor.userId();
if (!uid) {
  throw new Meteor.Error('not_authorized', 'Unauthorized');
}
await deleteOutgoingIntegration(integrationId, uid);

Try / catch

try {
  await deleteOutgoingIntegration(integrationId, uid);
} catch (err) {
  if (err instanceof Meteor.Error && err.error === 'not_authorized') {
    // resolve a valid authenticated userId before retrying
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling the exported helper with undefined/empty userId — e.g. a custom wrapper forwarding Meteor.userId() while logged out, or a REST-style handler reading a missing X-User-Id.

Common situations: Custom server code reusing the helper without an auth check; method wrappers that forward this.userId unconditionally.

Understand the failure class

Related errors


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