RocketChat/Rocket.Chat · error · Meteor.Error
error-not-authorized
error-not-authorized
Error message
Not authorized
What it means
The user is authenticated, but hasPermissionAsync(userId, 'view-join-code') returned false, so getRoomJoinCode refuses with 'error-not-authorized'. The view-join-code permission is admin-oriented by default; ordinary members and even room owners typically do not hold it.
Source
Thrown at apps/meteor/server/meteor-methods/rooms/getRoomJoinCode.ts:27
declare module '@rocket.chat/ddp-client' {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface ServerMethods {
getRoomJoinCode(rid: string): string | false;
}
}
/* @deprecated */
Meteor.methods<ServerMethods>({
async getRoomJoinCode(rid) {
check(rid, String);
const userId = Meteor.userId();
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getJoinCode' });
}
if (!(await hasPermissionAsync(userId, 'view-join-code'))) {
throw new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'getJoinCode' });
}
const room = await Rooms.findById(rid);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return Boolean(room) && (isRoomWithJoinCode(room!) ? room.joinCode : false);
},
});
View on GitHub (pinned to b2c16d5842)
Solutions
- Grant view-join-code to the user's role in Administration -> Permissions
- Assign the user a role (e.g. admin) that already holds view-join-code
- Have an admin fetch the join code and share it through a controlled channel instead
- If the feature is not needed, remove the call - join codes are sensitive room credentials
Example fix
// before - any member UI tries to read the join code
const code = await Meteor.callAsync('getRoomJoinCode', rid);
// after - only render the affordance for users with the permission
const canView = await Meteor.callAsync('getUserPermission', 'view-join-code'); // or track roles client-side
if (!canView) return null;
const code = await Meteor.callAsync('getRoomJoinCode', rid); Defensive patterns
Strategy: try-catch
Validate before calling
// hide the affordance unless the user's roles plausibly hold the permission
const roles = Meteor.user()?.roles ?? [];
const canProbablyView = roles.includes('admin'); // conservative client-side check
if (!canProbablyView) return null;
const code = await Meteor.callAsync('getRoomJoinCode', rid); Type guard
const isJoinCode = (v: string | false): v is string => typeof v === 'string';
Try / catch
try {
const code = await Meteor.callAsync('getRoomJoinCode', rid);
} catch (e) {
if (e instanceof Meteor.Error && e.error === 'error-not-authorized') {
// permission denied - degrade gracefully instead of surfacing an error
showJoinCodeUnavailable();
}
} Prevention
- Check the permission matrix (Administration -> Permissions -> view-join-code) before shipping join-code features
- Gate join-code UI on role membership, not on room ownership
- Avoid caching join codes - permissions can be revoked at any time
When it happens
Trigger: A non-admin user calls Meteor.call('getRoomJoinCode', rid); a custom role was created without the view-join-code permission; the permission was revoked from a role after code that depended on it shipped.
Common situations: Apps or UI features surfacing join codes to regular users; permission matrix edits in Administration -> Permissions that dropped view-join-code; enterprise roles provisioned without the admin default set.
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/6ae0fc3963757ed0.
Report an issue: GitHub.