Ideal flow for creating admin users

Back again, now that I’ve been able to dockerize Meteor and can get moving. I’m adding user functionality to my code, which is a big reason why I’ve come back to Meteor for this project (I didn’t really want to build out an entire user/auth ecosystem yet again). I’m making slow progress, but I’m thinking about how to best have the website set up to have one existing admin user when it gets deployed somewhere new, like the cloud.

Shelling in to the db manually and doing it that way seems silly. I see that we can set up startup stuff in meteor methods, so I was thinking about leveraging that to create my user. Obviously I don’t want to check in my password, and potentially not my email to Github or something, however, so IF this is the right flow, I’d need to store it somewhere else.

It can’t be the db, since it’ll be a blank db. Perhaps a config file under the private directory? And just don’t check that in? Thoughts? Kind of a chicken/egg problem here.

For users after that, I’ll implement a UI to manage roles (probably using this alanning package) and user accounts, but I need an initial admin.

You can leverage Meteor’s private settings config for the initial admin account. Just take note of the following:

  1. Never commit that file with the production values
  2. Startup is not a good place to do this since it will be executed everytime you deploy. I’d rather add a simple route instead to create the admin account
  3. Generate a password and send to the account. This way, you only specify the admin email or mobile number on the settings and not the password
1 Like

If you use enrollment emails anyway, just put something along these lines in Meteor.startup():

if (!Meteor.users.findOne()) {
	const userId = Accounts.createUser({
		email: 'user@example.com',
		profile: {name: 'John Doe'},
	});

	// ....probably do stuff here to make the user admin
	Users.findOne(userId).save({...});

	Accounts.sendEnrollmentEmail(userId);
}

So, if no users are found (on your blank db), it will create the first admin user and send him an enrollment email so he can create a password.
If you do not want email and/or name checked in to your repository, put it in i.e settings.json

I do it this way, which I believe is as simple as it gets.

2 Likes

Yeah, I use the same approach as @janka and it’s easy as. Strongly recommend

I do essentially the same approach as @janka as well, though I don’t make use of the enrollment email.

if ( Meteor.users.find().count() === 0 ) {
    Accounts.createUser({
        username: 'someAdminHandle',
        email: 'boss@some.domain',
        password: Random.id([20]),
        profile: {
            firstname: 'Boss',
            lastname: 'Human'
        }
    });
    // other stuff
}

So whenever I stand up a new server instance, I know my email will have an account along with some unknown password, so I just use the lost password feature and I’m all set.

Note: this approach assumes you have great security with whichever email is used.

Edit: I’m curious if anyone knows whether using .findOne() is faster than the .count() method on the mongo cursor. I’m guessing it’s not an issue unless the users collection is massive, but just curious.

.count() has the same query performance as .find().fetch() and has been deprecated since MongoDB 4.0. Not sure what Meteor is doing behind the scene

1 Like

Ah, interesting. I haven’t seen any errors thrown but now I’ll look into it. Thanks for pointing that out.

MongoDB seems to follow a two-level deprecations: deprecate in documentation first, then deprecate in console. If you are using MongoDB 5.0, it might have appeared in the console. We are still using 4.x but we also moved to rawCollection().countDocuments() since seeing the deprecation from the docs