diff --git a/bigbluebutton-html5/imports/startup/server/userPermissions.js b/bigbluebutton-html5/imports/startup/server/userPermissions.js
index 4fea3ba0ea46af05952924788959e010afec6cb2..750e536580db121b8f8a0c385275e024f87438a3 100755
--- a/bigbluebutton-html5/imports/startup/server/userPermissions.js
+++ b/bigbluebutton-html5/imports/startup/server/userPermissions.js
@@ -129,12 +129,23 @@ export function isAllowedTo(action, credentials) {
   });
 
   const allowedToInitiateRequest =
-    null != user &&
-    authToken === user.authToken &&
+    user &&
+    user.authToken === authToken &&
     user.validated &&
-    user.user.connection_status === 'online' &&
-    'HTML5' === user.clientType &&
-    null != user.user;
+    user.clientType === 'HTML5' &&
+    user.user &&
+    user.user.connection_status === 'online';
+
+  const listOfSafeActions = [
+    'logoutSelf',
+  ];
+
+  const requestIsSafe = listOfSafeActions.includes(action);
+
+  if (requestIsSafe) {
+    logger.info(`permissions: requestIsSafe for ${action} by userId=${userId} allowed`);
+    return true;
+  }
 
   if (allowedToInitiateRequest) {
     let result = false;
diff --git a/bigbluebutton-html5/imports/ui/services/auth/index.js b/bigbluebutton-html5/imports/ui/services/auth/index.js
index ec00d61c6ed85faf69c4e4f855a765aefe63b207..4ea2e8bc0cd9a0d12870b5e0b33ddbb74d1e5e46 100755
--- a/bigbluebutton-html5/imports/ui/services/auth/index.js
+++ b/bigbluebutton-html5/imports/ui/services/auth/index.js
@@ -4,7 +4,7 @@ import { Tracker } from 'meteor/tracker';
 import Storage from '/imports/ui/services/storage/session';
 
 import Users from '/imports/api/users';
-import { makeCall } from '/imports/ui/services/api';
+import { makeCall, logClient } from '/imports/ui/services/api';
 
 const CONNECTION_TIMEOUT = Meteor.settings.public.app.connectionTimeout;
 
@@ -89,10 +89,22 @@ class Auth {
     }
 
     return new Promise((resolve, reject) => {
-      makeCall('userLogout').then(() => {
-        this.fetchLogoutUrl()
+      const credentialsSnapshot = {
+        meetingId: this.meetingID,
+        requesterUserId: this.userID,
+        requesterToken: this.token,
+      };
+
+      // make sure users who did not connect are not added to the meeting
+      // do **not** use the custom call - it relies on expired data
+      Meteor.call('userLogout', credentialsSnapshot, (error, result) => {
+        if (error) {
+          logClient('error', { error, method: 'userLogout', credentialsSnapshot });
+        } else {
+          this.fetchLogoutUrl()
           .then(this.clearCredentials)
           .then(resolve);
+        }
       });
     });
   };
@@ -109,6 +121,13 @@ class Auth {
 
     return new Promise((resolve, reject) => {
       Tracker.autorun((c) => {
+        if (!(credentials.meetingId && credentials.requesterToken && credentials.requesterUserId)) {
+          return reject({
+            error: 500,
+            description: 'Authentication subscription failed due to missing credentials.',
+          });
+        }
+
         setTimeout(() => {
           c.stop();
           reject({