Accounts system is a must have if we want to talk about any app, even a very simple app. You’ll always need some user management system. I’ll show you how to build your own, customized account system based on Meteor's API and my package which is something similar to accounts-ui provided by Meteor or User Accounts package.

The sId package provides some forms (templates) and some logic. You’ll get a fully-functional login-register system. You’ll be able to configure your routes and other settings like validators, callback functions and messages. But what’s most important here is that you’ll be able to take the sId code and analyze it to learn more about accounts in Meteor. This package is simpler than User Accounts so you’ll be able to take a clearer path in learning. Also it’s more advanced than accounts-ui so you’ll learn how to prepare your own forms and how to connect it all together.

The main sId feature is that it is not dependent on any routing system. It is also very simple to configure and style.

What we will cover here is:

Meteor core Accounts API – short introduction,

Meteor accounts-ui package,

sId package introduction,

sId package in Scotty boilerplate – demo configuration,

Where you will learn more

Meteor Accounts

Meteor, in its core, has some useful API's for creating your own user account management. If you go and read an official documentation website, you'll find that there is quite a big section which is devoted to this topic. You can find it here: http://docs.meteor.com/#/full/accounts_api

We'll take a look at some of them. As you can see, Meteor has something like an accounts-ui package, which we'll get back to later. For now, let's look at some of the basic methods. I mean:

All of these methods have very good documentation where you can read how to use it and where (client/server). Also the names are very descriptive. In brief - we have here the method for creating a new user which requires a username, password, e-mail, we have methods which are responsible for logging in the user, and you can also use external services like Facebook or Google. We’ll talk more about that later. There is also a very important method – Accounts.onCreateUser which lets you manipulate the user data object and save it after it’s modified. So you’re able to add additional fields and information to your newly created user. You will read more about later on in the article.

These methods are all you need to create new users and to manage register and login users. You just need to prepare your own forms and configure all events which will fire these methods. Then Meteor will do all the stuff you need. It will add a new user to the users collection with special preconfigured fields like e-mails, tokens etc. so you don't bother yourself with it. You can always go and see how the collection looks. Just open your mongo console by 'meteor mongo' command or use any client for mongo databases like, for example, RoboMongo.

Let’s see what accounts-ui really is.

First of all you need to know that this package is maintained by Meteor Development Group so it’s used very often. This is a simple UI system prepared for Accounts API.

This package exists because you probably need some UI for your accounts logic and this package provides it. Of course you can do it by yourself or use any other package and this is what we'll be talking about later on.

To use accounts-ui package all you need to do is add the package by:

$ meteor add accounts-ui

Then you need to configure your accounts. See the documentation here: http://docs.meteor.com/#/full/accountsui

Basically you need to place the template with buttons and forms which is called loginButtons and then you can use Accounts.ui.config to configure your accounts package. Go here for more information: http://docs.meteor.com/#/full/accountsuiconfig

That's it! You have your accounts configured and you’ll get a small pop-up which will show the register or login form.

So why the sId package? Or why the User Accounts package? These are very good questions. Firstly, sId is simpler than User Accounts. It is better to style and also it is not dependent on routing. Don't get me wrong - User Accounts is the best package available right now. So why have I built sId? The answer is simple. I needed more control. I needed something simpler than User Accounts and something much more customizable than accounts-ui. Of course you can choose the package you think suits you best. User Accounts is really great and it has many separate packages which support many well known css frameworks like Bootstrap, Semantic UI and Foundation. The sId package provides custom styling, but you can configure your own classes and style it by hand. More about it later.

sId package introduction

sId is a standard Meteor package. You just need to add it by:

$ meteor add juliancwirko:s-id

Then you need to create a config file somewhere. It should be accessible on both sides (client and server). Below there is an example of content of such file:

Meteor.startup(function () { sId.config({ registerForm: { mainClass: 's-id-register-form', // css class for main container - you can change it and style it like you want in your app title: 'Register', // form title leadText: 'Hi, join us!', // form description text submitBtnLabel: 'Register' // button label text }, loginForm: { mainClass: 's-id-login-form', title: 'Login', leadText: 'Beam me up, Scotty!', submitBtnLabel: 'Login' }, forgotPassForm: { mainClass: 's-id-forgot-password-form', title: 'Forgot Password', leadText: 'Please fill in email address!', submitBtnLabel: 'Send New!' }, resetPassForm: { mainClass: 's-id-reset-password-form', title: 'Reset Password', leadText: 'Please fill in new password!', submitBtnLabel: 'Set New!' }, socialButtons: { // disable/enable social login/register buttons 'github': true, 'google': true, 'twitter': true, 'facebook': true, 'labels': { // labels for social buttons 'github': 'GitHub Access', 'google': 'Google Access', 'twitter': 'Twitter Access', 'facebook': 'Facebook Access' } }, // turn on e-mail verification.. without it user is still able to login, you can block it in the app by // checking e-mail verified field emailVerification: true, // change it to 'true' if you need only e-mail field on register form (default there is username and e-mail) registerEmailFieldOnly: false, // you can pass empty messages object to turn it off messages: { verifyEmail: 'Verify your e-mail address', verifiedEmail: 'Your email address was verified. Thanks!', somethingWrong: 'Something went wrong! Here is the error message: ', fillAllFields: 'Fill in all fields!', loginNow: 'You can login now.', sending: 'Sending...', validEmail: 'E-mail should be a valid e-mail address!', validPassword: 'Password should be at least one number, one lowercase and one uppercase letter and at least six characters!', validUsername: 'Username should be at least 3 characters long and max 12 characters!', // placeholders loginNamePlaceholder: 'Username or E-mail', usernamePlaceholder: 'Username', passwordPlaceholder: 'Password', emailPlaceholder: 'E-mail', newPasswordPlaceholder: 'New password' }, // should return true or false - you can overwrite these functions in your app sId config... // also remember to adjust your error messages (config above) validateUsername: function (username) { var min = 3; var max = 12; if (username && username.length >= min && username.length <= max) { return true; } return false; }, validatePassword: function (password) { var r = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}/; if (password && r.test(password)) { return true; } return false; }, validateEmail: function (email) { var r = /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; if (r.test(email)) { return true; } return false; }, onLogged: function () { // callback after successful login // it could be for example Router.go('/') or FlowRouter.go('/dashboard') or any other }, onRegistered: function () { // callback after successful registration }, onForgotPassword: function () { // callback after successful on forgot password action }, onResetPassword: function () { // callback after successful password reset }, getPasswordResetToken: function () { // here you should return reset password tokent from your route param // you should have configured route: '/reset-password/:resetToken', // then with Iron Router you can do something like: // // With Iron Router // return Router.current().params.resetToken; or with Flow Router // or with Flow Router // return FlowRouter.getParam('resetToken'); } }); });

I will try to explain all the config options.

The config should be fired in the Meteor.startup hook. First of all, you might want to configure your main forms like register form or login form. For example, if I want to configure my register form I should use the fragment from the config file:

(...) registerForm: { mainClass: 's-id-register-form', title: 'Register', leadText: 'Hi, join us!', submitBtnLabel: 'Register' } (...)

What we've got here:

mainClass is the main container class which is used for custom styling. You can provide any other name here and then you can inspect the form structure to get other subclasses. Then you’ll be able to style it as you want using the configured namespace (mainClass name)

is the main container class which is used for custom styling. You can provide any other name here and then you can inspect the form structure to get other subclasses. Then you’ll be able to style it as you want using the configured namespace (mainClass name) title is a very self explanatory. You can configure the main title of your form here.

is a very self explanatory. You can configure the main title of your form here. leadText is some kind of description under the title. You can provide an empty string here if you don't want to use it

is some kind of description under the title. You can provide an empty string here if you don't want to use it submitBtnLabel is a label of your register form submit button

The same goes for other forms like loginForm , forgotPassForm and resetPassForm .

Next in the config file we have social login buttons configuration. Basically this is a functionality which allows you to login through Facebook, Google or Twitter accounts. You can enable or disable particular services here. You can also configure labels for login/register buttons.

Remember that this part needs additional work to be done first. You need to generate your social services API keys and prepare the Meteor App. This can't be auto-configured by a package.

I will cover more in the next section of this article where I’ll be talking about the real demo app with sId, all based on the Scotty Meteor boilerplate.

Next we have some single config keys:

emailVerification turns e-mail verification on/off. Basically it places a flag in the user collection. Anyway, without any other work, the user is still able to login, but you can prevent it in the app by checking 'verified' flag in the user collection. If this option is turned on, the user will get an e-mail with a verification url.

turns e-mail verification on/off. Basically it places a flag in the user collection. Anyway, without any other work, the user is still able to login, but you can prevent it in the app by checking 'verified' flag in the user collection. If this option is turned on, the user will get an e-mail with a verification url. registerEmailFieldOnly turns the username field on/off (leaves only e-mail field) on the registration form. Sometimes it’s not necessary to have a username when you have an e-mail. Meteor can create a user without a username. So this is the option to enable or disable the username field.

There are also some messages and placeholders which you can provide. It is useful when you want some not standard messages or other language strings. It is all self explanatory and it is very descriptive too.

We have some validators here too. They are all functions which should return true or false.

validateUsername – it takes the username as an argument and returns true or false. You can provide your own validator logic here but standard logic is provided. If you want to disable the validation, just return true. You can also provide the error message above in the messages section. The key for it is 'validUsername'

– it takes the username as an argument and returns true or false. You can provide your own validator logic here but standard logic is provided. If you want to disable the validation, just return true. You can also provide the error message above in the messages section. The key for it is 'validUsername' validatePassword – it takes the password as an argument and also returns true or false. The key for error message here is 'validPassword'. You can also disable it by returning true.

– it takes the password as an argument and also returns true or false. The key for error message here is 'validPassword'. You can also disable it by returning true. ValidateEmail – it takes the e-mail as an argument and returns true or false. The key for error message here is 'validEmail'.

Last but not least – we have some callbacks here which are very important in this package:

onLogged – a function without arguments. It will be fired when the user logs in. You can use it for redirections or for other important calls.

– a function without arguments. It will be fired when the user logs in. You can use it for redirections or for other important calls. onRegistered - callback after successful registration

- callback after successful registration onForgotPassword - callback after successful on forgot password action

- callback after successful on forgot password action onResetPassword - callback after successful password reset

- callback after successful password reset getPasswordResetToken – here you should return the password reset token which you’ll get from url params. It depends on the routing you use. You can do with FlowRouter, for example, something like this:

getPasswordResetToken: function () { return FlowRouter.getParam('resetToken'); }

The package provides some of the templates with forms. You can place them anywhere you want. Just provide the routing logic and it’s not important which router you use.

Ok, let’s see how it looks in the real demo app. You’ll learn how to implement the sId package and you’ll be able to understand the basic concepts of accounts in the Meteor app.

You can also go back to the sId documentation. Go and read it here: http://s-id.meteor.com

sId package in Scotty boilerplate – demo configuration

What is Scotty? It is my simple boilerplate starter project for Meteor. You can see the code here: https://github.com/juliancwirko/scotty You can clone it and start your new Meteor App. It has some well-known community packages included and my s-alert and s-grid package. Of course it includes the s-id package too. It’s up-to-date with new the Meteor and all packages are also updated frequently because this is a tool which I use very often.

Ok so let's start with Scotty and sId inspection. Let's divide it into some steps which you should do with any new app when you want to use the sId package:

Step 1. When you clone the Scotty project you'll see that there is a file named users-accounts-config.js which is located in the common/settings folder. This is where you should start. Here is the config file which was described above. You can read it and see how the callbacks are used and all other config options. You can customize it here as well.

Step 2. If you run the Scotty app you’ll see that there are some routes like login, register. These are standard FlowRouter routes in the app. You can go and see routes configuration file in common/router/routes.js . What is important here is how we have configured the sId routes. At the end of the file you'll find four routes. We use BlazeLayout here which loads templates provided by the sId package. These are:

sIdLoginView

sIdRegisterView

sIdForgotPasswordView

sIdResetPasswordView

So the main concept is to make use of the provided templates which has its own logic. All that you need to do is glue them with some routes or other logic. (also with callbacks in the config file) You could also use them without routes. This was the main concept of the package – not to tie this to the routing.

Step 3. Now we need to configure our external social services. We’ll be able to login with Facebook, Google, Twitter or GitHub (for now these are the only supported services). This configuration requires some work outside our app. You need to gain some API keys. You can find more information on the Internet and also on these websites:

for Google API: https://console.developers.google.com/

for Facebook API: https://developers.facebook.com/apps

for Twitter API: https://apps.twitter.com/

for GitHub API: https://github.com/settings/applications/

You should provide such data:

{ "private": { "github": { "clientId": "{your github API client id here}", "secret": "{your google API secret key here}" }, "google": { "clientId": "{your google API client id here}", "secret": "{your google API secret key here}" }, "twitter": { "consumerKey": "{your twitter API customer key here}", "secret": "{your twitter API secret key here}" }, "facebook": { "appId": "{your facebook API app id here}", "secret": "{your facebook API secret key here}" } } }

You need to place it in your settings.json file and run (or deploy) your Meteor app with the --settings flag providing a path to your settings.json file. You will find the demo settings.json file in the Scotty app example too. This is all you need to make the external services login/register work.

Step 4. What if we want to transform or add some additional data to our user collection in the creation process? There is a method for that in Meteor Accounts API which I mentioned it above. It is called Accounts.onCreateUser . You can see the example in the Scotty demo app. Just go and open the file located in server/settings/accounts.js . As you can see, the method takes an argument which is a function with user object as an argument. For example, if I want to register by Facebook and I want to transform my data I could do something like:

Accounts.onCreateUser(function (options, user) { if (user.services.facebook) { user.username = user.services.facebook.email; user.emails = []; user.emails.push({ address: user.services.facebook.email, verified: true }); return user; } return user; });

I have transformed the user object and returned it. You can also add new data to the user object. It’s up to you what you do with the Accounts.onCreateUser() function.

You can find a complete config for it in the server/settings/accounts.js file.

Also remember that you should configure your e-mail service like, for example, Mailgun. You can do this in a couple of ways. One way is to set up your environment variable. See the server/settings/accounts.js .

Step 5. Styling. I’m not a very big fan of Bootstrap everywhere. So you won’t find the standard Bootstrap (or other css frameworks) styling classes here. Of course the sId package provides some custom styling, but because of simple main css classes configuration and styling by namespaces, you can simply unstyle all forms. Just rename or delete the 'mainClass' config key. You can provide your own namespace here and style your forms. All form elements have their own uniq classes. Go and see an example css file here: https://github.com/juliancwirko/meteor-s-id/blob/master/client/style.css If you need more customization, you can try to overwrite templates using the aldeed:template-extension package

Where you will learn more

There are plenty of resources available on the Internet. But here you have some articles/websites which are very good:

Summary

What I wanted to share here is an example of a very simple and very useful package which provides a configurable Meteor Accounts UI system. Of course you can use accounts-ui or User Accounts or even write your own package. I only hope that this article and sId package helps you to better understand Meteor Accounts API and UI elements relations.

Also check out the Scotty boilerplate. It might be very useful when you want to start your new Meteor App. Let me know about all your opinions and ideas. Thanks!

Have a cool project in mind? -> psd2Meteor - Meteor apps development!