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
- Resolve and assert an authenticated userId before invoking the helper
- Prefer the shipped method wrapper or POST /v1/integrations.remove, which perform auth themselves
- 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
- Never forward Meteor.userId() unconditionally — assert it first
- Prefer the shipped wrappers and REST endpoints that handle auth
- Type the helper parameter as string (not string | null) so falsy ids fail at compile time
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/144516f659bf61e0.
Report an issue: GitHub.