Prevent client from calling server-side methods

Hello, so I have a login form that accepts a username and password. Before the user is logged in, I need to check if their account exists and is enabled. I’ve accomplished that using the code below. The problem is, the server-side method that does the checking, is_user_enabled, can be accessed by the client via the browser console. Usually I can prevent this by doing:

my_method : function(doc) {
    if (is_admin()) {
        // Only admins can run this method.
    }
}

But in the case of is_user_enabled, the user is not logged in yet. So, my question is, what is the correct way to handle this situation?

My code:

client/login.html

{{#autoForm schema=get_login_form_schema id="login_form"}}
	{{> flashMessages}}
	<fieldset>
		<!-- <legend>Create User</legend> -->
		{{> afQuickField name="username" placeholder="schemaLabel" label=false}}
		{{> afQuickField name="password" placeholder="schemaLabel" type="password" label=false}}
		<div>
			<button type="submit" class="btn btn-primary">Login</button>
		</div>
	</fieldset>
{{/autoForm}}

client/lib/helpers.js

AutoForm.hooks({
    login_form: {
        onSubmit: function (insert_doc, update_doc, current_doc) {
            Meteor.call("is_user_enabled", insert_doc, function(error, result) {
                if (result) {
                   // Try to log user in via Meteor.loginWithPassword()
                 }
            });
         }
    }
});

server/lib/methods.js

Meteor.methods({
    is_user_enabled : function(doc) {
        // Used by the login form. Returns true if user exists and account is enabled.
        check(doc, schemas.login);
        var user = Meteor.users.findOne({username: doc.username}, {fields: {status: 1}});
        if (user.status === "enabled") {
            return true;
        }
    }
});

Calling Meteor.userId(); will tell you if the current user is logged in or not.

if ( user.status === "enabled" &&  Meteor.userId() ) {
        return true;
    }

You cannot stop a client from calling a meteor method (that’s what they’re designed for!)

I’d use the Accounts.validateLoginAttempt()

Accounts.validateLoginAttempt(function (info) {
  // Make sure user object exists and is enabled
  if (info.user && info.user.status !== "enabled") {
    throw new Meteor.Error("account-not-enabled");
  }
});

http://docs.meteor.com/#/full/accounts_validateloginattempt

or just use a plain function

1 Like

this.userId; in methods

Why use method when you want server side function ?

May I reply?

I just stumbled over that question since I have a similar issue.

@shock, I can answer your question:

I need to get some property from a collection. In the normal case it need to call the server since I didn’t publish this data to the client. But in some cases it might be that the data is already on the client. In that case: why should I still call the server if I already have everything on the client!