Meteor JS (Part 6): Authentication & Authorization

This is a post in a multiple part series on getting started with Meteor JS. If you don’t have Meteor JS installed you will want to start at  the first post in the series. Part 2 is where we start building the application.

If you would like to follow along I have tagged the git repository on Github at the starting point for this post. Here is the URL to the tag

https://github.com/dhirshjr/pricebook/releases/tag/v0.5.0

By default the insecure and autopublish packages are part of every meteor project. Autopublish publishes all records from every collection. Insecure allows full CRUD operations against all collections. In this post we are going to remove autopublish and insecure. We will also enable authentication and authorization.

So let’s get started.

Remove Autopublish

The reason we need to remove autopublish is because it publishes all collections to the client. We don’t want this because once we have a users collection then all details of all of our users will be published. This includes all email addresses, encrypted passwords, oauth refresh tokens, etc.

First we will remove autopublish by running the following.

If you have the application running you will notice that the data is gone. We are no longer publishing everything. We will need to create a publication on the server and a subscription on the client.

Let’s add the following code to server/publications/items/item.js. The path to this file doesn’t exist yet. I had to run mkdir -p server/publications/items from the terminal before creating the file.

The Meteor.publish method is taking in two arguments. First, we give the publication the name of allItems. Next, we pass in a function that returns a collection cursor. This completes us getting set up on the server side.

Next we will add a the following to the top of client/views/items/itemlist.js.

Remove Insecure

At this point we only have access to data that the server has published. The only problem is that we can run insert, update, and remove against anything that has been published. Next we are going to remove the insecure package. Once we remove insecure we will not be able to make any changes to the published data.

Run the following, at the terminal, to remove insecure from our project. After running this try to modify data within the application.

To restore our ability to modify the data we are going to need to do a few things.

First we will need to call the allow function on our Items collection. This function takes in an object that specifies the rules that allow someone to modify data. Let’s add the following code to both/collections/items.js just below the creation of the Items collection.

As you can see we are passing in a function for each modification operation. If you look closely you will notice that these functions are taking in a user ID. At this point we are not authenticating so it will be null and we still won’t be able to modify anything.

Authentication and Authorization

It is pretty easy to add an accounts system to our project. Since we are using Semantic UI I thought that it would be important to find a system that supported our front end UI library. For this project are going to use useraccounts package. Just run the following to install.

That last package might leave you scratching your head a little. Useraccounts:core allows us to plugin whatever accounts authentication package we want. There are several others. For example take a look at accounts-google or accounts-github.

The useraccounts:core package is going to change quite a bit. The biggest change is that it is going to add iron:router to our project. Iron router will allow us to do a lot in the future so let’s go ahead and make the changes needed for migrate to using Iron Router.

First, let’s create our routes. Let’s create the file both/routes.js and put the following code into it.

First, we are telling the useraccounts that we want to configure the signIn route. This will allow us to sign in by navigating to /sign-in and get a login/registration page. Next, We are configuring our layoutTemplate to point to a template named layout. We will create the layout template next. Finally, we are configuring a route for the root of our application and this route will render the itemList template.

Next, let’s create the layout template. Create a file at client/views/layouts/layout.html and add the following code.

You should notice something new in this template. Instead of hard coding the {{> itemList}} inclusion tag, we are now using a {{> yield}}. This is simply saying this is where we put the template specified by the render method in our route definition.

Now, at this point we need to go back to pricebook.html and clear out the body tag. Your body tag in the pricebook.html file should look like the following now.

At this point you should be able to register accounts and sign in. But you still won’t be able to add or modify anything. The reason is that our allow rules are looking for an owner property and it simply doesn’t exist yet. The owner property will simply be the unique Mongo ID of the user that is logged in. To get the userId into the owner property let’s add the collection hooks package by running the following.

This package installs several hooks that we can tap into. The hook we are going to use is before.insert.

Let’s add the following code to the both/collections/items.js file just after the Items collection definition.

The code in the callback will run on the client and server. I encourage you to take a look at all of the documentation for the collection hooks package on Github.
https://github.com/matb33/meteor-collection-hooks

We also need to update our simple schema for the Items collection. If we don’t then we still won’t be able to make any changes. In the same file add the following code to add owner to the schema.

At this point you might want to reset all of the data in the project. The owner property won’t exist on any preexisting data. To reset the project let’s run the following from the terminal. If meteor is running let’s stop it before running the reset.

Now let’s try creating some users and adding some data. This should work at this point. One thing to note is that a user will only be able to modify records that they own. In the next section we will modify the UI to show this.

UI

Now a user can insert items and modify items that they own. But it might be a little confusing to leave things how they are. A user might not understand why a change was rejected. A better way of handling this is to have the UI let the user know they cannot add or edit.

First, let’s create a UI helper that we will be able to use in any of our templates. Let’s create client/lib/helpers.js to store our global template helpers. Let’s add the following code to helpers.js.

We are putting the helpers.js file into the lib directory, because meteor will load all files in the lib directory before any other files under the client directory.

Then, let’s modify the addItem template to only show the form when a user is logged in. Modify client/views/items/addItem.html to look like the following.

This will use our new isLoggedIn global helper.

As a side note, you might have to sign out and back in again to get the add items button to work.

We only need to modify a few more files.

In client/views/items/itemlist.html let’s hide the last column of the header if a user isn’t logged in.

In client/views/items/item.html let’s hide the last column of an item row if a user isn’t logged in.

This will only show the edit and delete buttons if we are logged in and own the item. Notice that once you save this file even if you are logged in you cannot see the edit and delete buttons. That is because we used a new template helper called canEdit. We need to add that to the client/views/items/item.js file.

Summary

In this post we removed packages that made our application insecure. We explicitly stated what data we wanted to publish to the client. We added authorization rules and authentication. If you have any questions leave a comment on this blog or send me a tweet on twitter to @dhirshjr. And as always the code from this post is up on Github at the following URL.

https://github.com/dhirshjr/pricebook

3 thoughts on “Meteor JS (Part 6): Authentication & Authorization”

  1. Another very nice post, thank you. A few comments:
    1) “We need to call the allow function”, maybe ‘include’ would be better since Meteor does the calling, as I understand it.
    2) The user accounts package works fine but does not show the user who is currently signed in, as the ‘accounts-ui-bootstrap-dropdown’ package does. Is there a reason for this?
    3) Two typos: smoeone, sevral.
    All logic works well, very useful thankyou.

    1. Hi Alan,

      Thank you again for providing input. I have corrected the spelling mistakes that you pointed out.

      On your first point, we are actually calling the allow function of the collection passing in an object with functions that meteor will call later.

      On your second point, it really isn’t too difficult to add the username/email address.

      In client/lib/helpers.js add the following.

      In client/views/layout/layout.html add the following just below the div containing the {{> atNavButton}} inclusion tag.

      I will include the above in the next release.

      Thank you,
      Douglas

  2. Hi Douglas, thanks for your quick reply.
    UI.registerHelper needs a closing ‘)’ and then works a treat.
    Best wishes.

Leave a Reply

Your email address will not be published. Required fields are marked *