diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php
index dd919c6c2..91cd4bd51 100644
--- a/app/Http/Controllers/BookController.php
+++ b/app/Http/Controllers/BookController.php
@@ -26,6 +26,7 @@ class BookController extends Controller
     {
         $this->bookRepo = $bookRepo;
         $this->pageRepo = $pageRepo;
+        parent::__construct();
     }
 
     /**
@@ -46,19 +47,21 @@ class BookController extends Controller
      */
     public function create()
     {
+        $this->checkPermission('book-create');
         return view('books/create');
     }
 
     /**
      * Store a newly created book in storage.
      *
-     * @param  Request  $request
+     * @param  Request $request
      * @return Response
      */
     public function store(Request $request)
     {
+        $this->checkPermission('book-create');
         $this->validate($request, [
-            'name' => 'required|string|max:255',
+            'name'        => 'required|string|max:255',
             'description' => 'string|max:1000'
         ]);
         $book = $this->bookRepo->newFromInput($request->all());
@@ -90,6 +93,7 @@ class BookController extends Controller
      */
     public function edit($slug)
     {
+        $this->checkPermission('book-update');
         $book = $this->bookRepo->getBySlug($slug);
         return view('books/edit', ['book' => $book, 'current' => $book]);
     }
@@ -98,14 +102,15 @@ class BookController extends Controller
      * Update the specified book in storage.
      *
      * @param  Request $request
-     * @param $slug
+     * @param          $slug
      * @return Response
      */
     public function update(Request $request, $slug)
     {
+        $this->checkPermission('book-update');
         $book = $this->bookRepo->getBySlug($slug);
         $this->validate($request, [
-            'name' => 'required|string|max:255',
+            'name'        => 'required|string|max:255',
             'description' => 'string|max:1000'
         ]);
         $book->fill($request->all());
@@ -123,6 +128,7 @@ class BookController extends Controller
      */
     public function showDelete($bookSlug)
     {
+        $this->checkPermission('book-delete');
         $book = $this->bookRepo->getBySlug($bookSlug);
         return view('books/delete', ['book' => $book, 'current' => $book]);
     }
@@ -135,6 +141,7 @@ class BookController extends Controller
      */
     public function destroy($bookSlug)
     {
+        $this->checkPermission('book-delete');
         $book = $this->bookRepo->getBySlug($bookSlug);
         Activity::addMessage('book_delete', 0, $book->name);
         $this->bookRepo->destroyBySlug($bookSlug);
diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php
index 12bbeeab0..98e7a6678 100644
--- a/app/Http/Controllers/ChapterController.php
+++ b/app/Http/Controllers/ChapterController.php
@@ -22,12 +22,13 @@ class ChapterController extends Controller
      * @param $bookRepo
      * @param $chapterRepo
      */
-    public function __construct(BookRepo $bookRepo,ChapterRepo $chapterRepo)
+    public function __construct(BookRepo $bookRepo, ChapterRepo $chapterRepo)
     {
         $this->bookRepo = $bookRepo;
         $this->chapterRepo = $chapterRepo;
+        parent::__construct();
     }
-    
+
 
     /**
      * Show the form for creating a new chapter.
@@ -37,6 +38,7 @@ class ChapterController extends Controller
      */
     public function create($bookSlug)
     {
+        $this->checkPermission('chapter-create');
         $book = $this->bookRepo->getBySlug($bookSlug);
         return view('chapters/create', ['book' => $book, 'current' => $book]);
     }
@@ -44,12 +46,13 @@ class ChapterController extends Controller
     /**
      * Store a newly created chapter in storage.
      *
-     * @param $bookSlug
+     * @param          $bookSlug
      * @param  Request $request
      * @return Response
      */
     public function store($bookSlug, Request $request)
     {
+        $this->checkPermission('chapter-create');
         $this->validate($request, [
             'name' => 'required|string|max:255'
         ]);
@@ -88,6 +91,7 @@ class ChapterController extends Controller
      */
     public function edit($bookSlug, $chapterSlug)
     {
+        $this->checkPermission('chapter-update');
         $book = $this->bookRepo->getBySlug($bookSlug);
         $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
         return view('chapters/edit', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]);
@@ -97,12 +101,13 @@ class ChapterController extends Controller
      * Update the specified chapter in storage.
      *
      * @param  Request $request
-     * @param $bookSlug
-     * @param $chapterSlug
+     * @param          $bookSlug
+     * @param          $chapterSlug
      * @return Response
      */
     public function update(Request $request, $bookSlug, $chapterSlug)
     {
+        $this->checkPermission('chapter-update');
         $book = $this->bookRepo->getBySlug($bookSlug);
         $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
         $chapter->fill($request->all());
@@ -121,6 +126,7 @@ class ChapterController extends Controller
      */
     public function showDelete($bookSlug, $chapterSlug)
     {
+        $this->checkPermission('chapter-delete');
         $book = $this->bookRepo->getBySlug($bookSlug);
         $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
         return view('chapters/delete', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]);
@@ -135,10 +141,11 @@ class ChapterController extends Controller
      */
     public function destroy($bookSlug, $chapterSlug)
     {
+        $this->checkPermission('chapter-delete');
         $book = $this->bookRepo->getBySlug($bookSlug);
         $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
-        if(count($chapter->pages) > 0) {
-            foreach($chapter->pages as $page) {
+        if (count($chapter->pages) > 0) {
+            foreach ($chapter->pages as $page) {
                 $page->chapter_id = 0;
                 $page->save();
             }
diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php
index 48a58ca99..2db96ccf7 100644
--- a/app/Http/Controllers/Controller.php
+++ b/app/Http/Controllers/Controller.php
@@ -2,27 +2,69 @@
 
 namespace Oxbow\Http\Controllers;
 
+use HttpRequestException;
 use Illuminate\Foundation\Bus\DispatchesJobs;
+use Illuminate\Http\Exception\HttpResponseException;
 use Illuminate\Routing\Controller as BaseController;
 use Illuminate\Foundation\Validation\ValidatesRequests;
 use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Session;
 use Oxbow\User;
 
 abstract class Controller extends BaseController
 {
     use DispatchesJobs, ValidatesRequests;
 
+    /**
+     * @var User static
+     */
+    protected $currentUser;
+    /**
+     * @var bool
+     */
+    protected $signedIn;
+
     /**
      * Controller constructor.
      */
     public function __construct()
     {
-        view()->share('signedIn', Auth::check());
+        // Get a user instance for the current user
         $user = Auth::user();
-        if(!$user) {
+        if (!$user) {
             $user = User::getDefault();
         }
-        view()->share('user', $user);
+        // Share variables with views
+        view()->share('signedIn', Auth::check());
+        view()->share('currentUser', $user);
+        // Share variables with controllers
+        $this->currentUser = $user;
+        $this->signedIn = Auth::check();
+    }
+
+    /**
+     * Checks for a permission.
+     *
+     * @param $permissionName
+     * @return bool|\Illuminate\Http\RedirectResponse
+     */
+    protected function checkPermission($permissionName)
+    {
+        if (!$this->currentUser || !$this->currentUser->can($permissionName)) {
+            Session::flash('error', trans('errors.permission'));
+            throw new HttpResponseException(
+                redirect()->back()
+            );
+        }
+
+        return true;
+    }
+
+    protected function checkPermissionOr($permissionName, $callback)
+    {
+        $callbackResult = $callback();
+        if ($callbackResult === false) $this->checkPermission($permissionName);
+        return true;
     }
 
 }
diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php
index ad87188b7..3ed1da4c1 100644
--- a/app/Http/Controllers/HomeController.php
+++ b/app/Http/Controllers/HomeController.php
@@ -19,12 +19,13 @@ class HomeController extends Controller
     /**
      * HomeController constructor.
      * @param ActivityService $activityService
-     * @param BookRepo $bookRepo
+     * @param BookRepo        $bookRepo
      */
     public function __construct(ActivityService $activityService, BookRepo $bookRepo)
     {
         $this->activityService = $activityService;
         $this->bookRepo = $bookRepo;
+        parent::__construct();
     }
 
 
diff --git a/app/Http/Controllers/ImageController.php b/app/Http/Controllers/ImageController.php
index 50341fe1f..6d01fe2cc 100644
--- a/app/Http/Controllers/ImageController.php
+++ b/app/Http/Controllers/ImageController.php
@@ -18,12 +18,13 @@ class ImageController extends Controller
     /**
      * ImageController constructor.
      * @param Image $image
-     * @param File $file
+     * @param File  $file
      */
     public function __construct(Image $image, File $file)
     {
         $this->image = $image;
         $this->file = $file;
+        parent::__construct();
     }
 
     /**
@@ -33,7 +34,7 @@ class ImageController extends Controller
      */
     public function getImage(Request $request)
     {
-        $cacheTime = 60*60*24;
+        $cacheTime = 60 * 60 * 24;
         $path = storage_path() . '/' . $request->path();
         $modifiedTime = $this->file->lastModified($path);
         $eTag = md5($modifiedTime . $path);
@@ -43,20 +44,20 @@ class ImageController extends Controller
         $headers = [
             'Last-Modified' => $headerLastModified,
             'Cache-Control' => 'must-revalidate',
-            'Pragma' => 'public',
-            'Expires' => $headerExpires,
-            'Etag' => $eTag
+            'Pragma'        => 'public',
+            'Expires'       => $headerExpires,
+            'Etag'          => $eTag
         ];
 
         $browserModifiedSince = $request->header('If-Modified-Since');
         $browserNoneMatch = $request->header('If-None-Match');
-        if($browserModifiedSince !== null && file_exists($path) && ($browserModifiedSince == $headerLastModified || $browserNoneMatch == $eTag)) {
+        if ($browserModifiedSince !== null && file_exists($path) && ($browserModifiedSince == $headerLastModified || $browserNoneMatch == $eTag)) {
             return response()->make('', 304, $headers);
         }
 
-        if(file_exists($path)) {
+        if (file_exists($path)) {
             return response()->make(file_get_contents($path), 200, array_merge($headers, [
-                'Content-Type' => $this->file->mimeType($path),
+                'Content-Type'   => $this->file->mimeType($path),
                 'Content-Length' => filesize($path),
             ]));
         }
@@ -72,21 +73,21 @@ class ImageController extends Controller
     {
         $pageSize = 30;
         $images = DB::table('images')->orderBy('created_at', 'desc')
-            ->skip($page*$pageSize)->take($pageSize)->get();
-        foreach($images as $image) {
+            ->skip($page * $pageSize)->take($pageSize)->get();
+        foreach ($images as $image) {
             $image->thumbnail = $this->getThumbnail($image, 150, 150);
         }
         $hasMore = count(DB::table('images')->orderBy('created_at', 'desc')
-            ->skip(($page+1)*$pageSize)->take($pageSize)->get()) > 0;
+                ->skip(($page + 1) * $pageSize)->take($pageSize)->get()) > 0;
         return response()->json([
-            'images' => $images,
+            'images'  => $images,
             'hasMore' => $hasMore
         ]);
     }
 
     /**
      * Get the thumbnail for an image.
-     * @param $image
+     * @param     $image
      * @param int $width
      * @param int $height
      * @return string
@@ -99,7 +100,7 @@ class ImageController extends Controller
         $thumbFilePath = public_path() . $thumbPath;
 
         // Return the thumbnail url path if already exists
-        if(file_exists($thumbFilePath)) {
+        if (file_exists($thumbFilePath)) {
             return $thumbPath;
         }
 
@@ -108,7 +109,7 @@ class ImageController extends Controller
         $thumb->fit($width, $height);
 
         // Create thumbnail folder if it does not exist
-        if(!file_exists(dirname($thumbFilePath))) {
+        if (!file_exists(dirname($thumbFilePath))) {
             mkdir(dirname($thumbFilePath), 0775, true);
         }
 
@@ -124,13 +125,14 @@ class ImageController extends Controller
      */
     public function upload(Request $request)
     {
+        $this->checkPermission('image-create');
         $imageUpload = $request->file('file');
         $name = str_replace(' ', '-', $imageUpload->getClientOriginalName());
         $storageName = substr(sha1(time()), 0, 10) . '-' . $name;
-        $imagePath = '/uploads/images/'.Date('Y-m-M').'/';
-        $storagePath = public_path(). $imagePath;
+        $imagePath = '/uploads/images/' . Date('Y-m-M') . '/';
+        $storagePath = public_path() . $imagePath;
         $fullPath = $storagePath . $storageName;
-        while(file_exists($fullPath)) {
+        while (file_exists($fullPath)) {
             $storageName = substr(sha1(rand()), 0, 3) . $storageName;
             $fullPath = $storagePath . $storageName;
         }
@@ -147,12 +149,13 @@ class ImageController extends Controller
 
     /**
      * Update image details
-     * @param $imageId
+     * @param         $imageId
      * @param Request $request
      * @return \Illuminate\Http\JsonResponse
      */
     public function update($imageId, Request $request)
     {
+        $this->checkPermission('image-update');
         $this->validate($request, [
             'name' => 'required|min:2|string'
         ]);
@@ -169,6 +172,7 @@ class ImageController extends Controller
      */
     public function destroy($id)
     {
+        $this->checkPermission('image-delete');
         $image = $this->image->findOrFail($id);
 
         // Delete files
@@ -176,14 +180,14 @@ class ImageController extends Controller
         $fileName = basename($image->url);
 
         // Delete thumbnails
-        foreach(glob($folder . '/*') as $file) {
-            if(is_dir($file)) {
+        foreach (glob($folder . '/*') as $file) {
+            if (is_dir($file)) {
                 $thumbName = $file . '/' . $fileName;
-                if(file_exists($file)) {
+                if (file_exists($file)) {
                     unlink($thumbName);
                 }
                 // Remove thumb folder if empty
-                if(count(glob($file . '/*')) === 0) {
+                if (count(glob($file . '/*')) === 0) {
                     rmdir($file);
                 }
             }
@@ -194,7 +198,7 @@ class ImageController extends Controller
         $image->delete();
 
         // Delete parent folder if empty
-        if(count(glob($folder . '/*')) === 0) {
+        if (count(glob($folder . '/*')) === 0) {
             rmdir($folder);
         }
         return response()->json('Image Deleted');
diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php
index 5921fce3f..b59dd2446 100644
--- a/app/Http/Controllers/PageController.php
+++ b/app/Http/Controllers/PageController.php
@@ -20,8 +20,8 @@ class PageController extends Controller
 
     /**
      * PageController constructor.
-     * @param PageRepo $pageRepo
-     * @param BookRepo $bookRepo
+     * @param PageRepo    $pageRepo
+     * @param BookRepo    $bookRepo
      * @param ChapterRepo $chapterRepo
      */
     public function __construct(PageRepo $pageRepo, BookRepo $bookRepo, ChapterRepo $chapterRepo)
@@ -29,18 +29,20 @@ class PageController extends Controller
         $this->pageRepo = $pageRepo;
         $this->bookRepo = $bookRepo;
         $this->chapterRepo = $chapterRepo;
+        parent::__construct();
     }
 
     /**
      * Show the form for creating a new page.
      *
-     * @param $bookSlug
+     * @param      $bookSlug
      * @param bool $chapterSlug
      * @return Response
      * @internal param bool $pageSlug
      */
     public function create($bookSlug, $chapterSlug = false)
     {
+        $this->checkPermission('page-create');
         $book = $this->bookRepo->getBySlug($bookSlug);
         $chapter = $chapterSlug ? $this->chapterRepo->getBySlug($chapterSlug, $book->id) : false;
         return view('pages/create', ['book' => $book, 'chapter' => $chapter]);
@@ -50,14 +52,15 @@ class PageController extends Controller
      * Store a newly created page in storage.
      *
      * @param  Request $request
-     * @param $bookSlug
+     * @param          $bookSlug
      * @return Response
      */
     public function store(Request $request, $bookSlug)
     {
+        $this->checkPermission('page-create');
         $this->validate($request, [
-            'name' => 'required|string|max:255',
-            'html' => 'required|string',
+            'name'   => 'required|string|max:255',
+            'html'   => 'required|string',
             'parent' => 'integer|exists:pages,id'
         ]);
         $book = $this->bookRepo->getBySlug($bookSlug);
@@ -66,7 +69,7 @@ class PageController extends Controller
         $page->slug = $this->pageRepo->findSuitableSlug($page->name, $book->id);
         $page->priority = $this->bookRepo->getNewPriority($book);
 
-        if($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) {
+        if ($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) {
             $page->chapter_id = $request->get('chapter');
         }
 
@@ -103,6 +106,7 @@ class PageController extends Controller
      */
     public function edit($bookSlug, $pageSlug)
     {
+        $this->checkPermission('page-update');
         $book = $this->bookRepo->getBySlug($bookSlug);
         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
         return view('pages/edit', ['page' => $page, 'book' => $book, 'current' => $page]);
@@ -112,12 +116,13 @@ class PageController extends Controller
      * Update the specified page in storage.
      *
      * @param  Request $request
-     * @param $bookSlug
-     * @param $pageSlug
+     * @param          $bookSlug
+     * @param          $pageSlug
      * @return Response
      */
     public function update(Request $request, $bookSlug, $pageSlug)
     {
+        $this->checkPermission('page-update');
         $book = $this->bookRepo->getBySlug($bookSlug);
         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
         $this->pageRepo->updatePage($page, $book->id, $request->all());
@@ -145,7 +150,7 @@ class PageController extends Controller
     public function searchAll(Request $request)
     {
         $searchTerm = $request->get('term');
-        if(empty($searchTerm)) return redirect()->back();
+        if (empty($searchTerm)) return redirect()->back();
 
         $pages = $this->pageRepo->getBySearch($searchTerm);
         return view('pages/search-results', ['pages' => $pages, 'searchTerm' => $searchTerm]);
@@ -158,6 +163,7 @@ class PageController extends Controller
      */
     public function sortPages($bookSlug)
     {
+        $this->checkPermission('book-update');
         $book = $this->bookRepo->getBySlug($bookSlug);
         return view('pages/sort', ['book' => $book, 'current' => $book]);
     }
@@ -165,26 +171,27 @@ class PageController extends Controller
     /**
      * Saves an array of sort mapping to pages and chapters.
      *
-     * @param $bookSlug
+     * @param         $bookSlug
      * @param Request $request
      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
      */
     public function savePageSort($bookSlug, Request $request)
     {
+        $this->checkPermission('book-update');
         $book = $this->bookRepo->getBySlug($bookSlug);
         // Return if no map sent
-        if(!$request->has('sort-tree')) {
+        if (!$request->has('sort-tree')) {
             return redirect($book->getUrl());
         }
 
         // Sort pages and chapters
         $sortMap = json_decode($request->get('sort-tree'));
-        foreach($sortMap as $index => $bookChild) {
+        foreach ($sortMap as $index => $bookChild) {
             $id = $bookChild->id;
             $isPage = $bookChild->type == 'page';
             $model = $isPage ? $this->pageRepo->getById($id) : $this->chapterRepo->getById($id);
             $model->priority = $index;
-            if($isPage) {
+            if ($isPage) {
                 $model->chapter_id = ($bookChild->parentChapter === false) ? 0 : $bookChild->parentChapter;
             }
             $model->save();
@@ -201,6 +208,7 @@ class PageController extends Controller
      */
     public function showDelete($bookSlug, $pageSlug)
     {
+        $this->checkPermission('page-delete');
         $book = $this->bookRepo->getBySlug($bookSlug);
         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
         return view('pages/delete', ['book' => $book, 'page' => $page, 'current' => $page]);
@@ -216,6 +224,7 @@ class PageController extends Controller
      */
     public function destroy($bookSlug, $pageSlug)
     {
+        $this->checkPermission('page-delete');
         $book = $this->bookRepo->getBySlug($bookSlug);
         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
         Activity::addMessage('page_delete', $book->id, $page->name);
@@ -255,6 +264,7 @@ class PageController extends Controller
 
     public function restoreRevision($bookSlug, $pageSlug, $revisionId)
     {
+        $this->checkPermission('page-update');
         $book = $this->bookRepo->getBySlug($bookSlug);
         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
         $revision = $this->pageRepo->getRevisionById($revisionId);
diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php
index 07d2cac9d..0266d2671 100644
--- a/app/Http/Controllers/UserController.php
+++ b/app/Http/Controllers/UserController.php
@@ -6,7 +6,6 @@ use Illuminate\Http\Request;
 
 use Illuminate\Support\Facades\Hash;
 use Oxbow\Http\Requests;
-use Oxbow\Http\Controllers\Controller;
 use Oxbow\User;
 
 class UserController extends Controller
@@ -21,9 +20,9 @@ class UserController extends Controller
     public function __construct(User $user)
     {
         $this->user = $user;
+        parent::__construct();
     }
 
-
     /**
      * Display a listing of the users.
      *
@@ -32,7 +31,7 @@ class UserController extends Controller
     public function index()
     {
         $users = $this->user->all();
-        return view('users/index', ['users'=> $users]);
+        return view('users/index', ['users' => $users]);
     }
 
     /**
@@ -42,27 +41,32 @@ class UserController extends Controller
      */
     public function create()
     {
+        $this->checkPermission('user-create');
         return view('users/create');
     }
 
     /**
      * Store a newly created user in storage.
      *
-     * @param  Request  $request
+     * @param  Request $request
      * @return Response
      */
     public function store(Request $request)
     {
+        $this->checkPermission('user-create');
         $this->validate($request, [
-            'name' => 'required',
-            'email' => 'required|email',
-            'password' => 'required|min:5',
-            'password-confirm' => 'required|same:password'
+            'name'             => 'required',
+            'email'            => 'required|email',
+            'password'         => 'required|min:5',
+            'password-confirm' => 'required|same:password',
+            'role'             => 'required|exists:roles,id'
         ]);
 
         $user = $this->user->fill($request->all());
         $user->password = Hash::make($request->get('password'));
         $user->save();
+
+        $user->attachRoleId($request->get('role'));
         return redirect('/users');
     }
 
@@ -70,11 +74,14 @@ class UserController extends Controller
     /**
      * Show the form for editing the specified user.
      *
-     * @param  int  $id
+     * @param  int $id
      * @return Response
      */
     public function edit($id)
     {
+        $this->checkPermissionOr('user-update', function () use ($id) {
+            return $this->currentUser->id == $id;
+        });
         $user = $this->user->findOrFail($id);
         return view('users/edit', ['user' => $user]);
     }
@@ -82,23 +89,31 @@ class UserController extends Controller
     /**
      * Update the specified user in storage.
      *
-     * @param  Request  $request
-     * @param  int  $id
+     * @param  Request $request
+     * @param  int     $id
      * @return Response
      */
     public function update(Request $request, $id)
     {
+        $this->checkPermissionOr('user-update', function () use ($id) {
+            return $this->currentUser->id == $id;
+        });
         $this->validate($request, [
-            'name' => 'required',
-            'email' => 'required|email',
-            'password' => 'min:5',
-            'password-confirm' => 'same:password'
+            'name'             => 'required',
+            'email'            => 'required|email',
+            'password'         => 'min:5',
+            'password-confirm' => 'same:password',
+            'role'             => 'exists:roles,id'
         ]);
 
         $user = $this->user->findOrFail($id);
         $user->fill($request->all());
 
-        if($request->has('password') && $request->get('password') != '') {
+        if ($this->currentUser->can('user-update') && $request->has('role')) {
+            $user->attachRoleId($request->get('role'));
+        }
+
+        if ($request->has('password') && $request->get('password') != '') {
             $password = $request->get('password');
             $user->password = Hash::make($password);
         }
@@ -113,6 +128,9 @@ class UserController extends Controller
      */
     public function delete($id)
     {
+        $this->checkPermissionOr('user-delete', function () use ($id) {
+            return $this->currentUser->id == $id;
+        });
         $user = $this->user->findOrFail($id);
         return view('users/delete', ['user' => $user]);
     }
@@ -120,11 +138,14 @@ class UserController extends Controller
     /**
      * Remove the specified user from storage.
      *
-     * @param  int  $id
+     * @param  int $id
      * @return Response
      */
     public function destroy($id)
     {
+        $this->checkPermissionOr('user-delete', function () use ($id) {
+            return $this->currentUser->id == $id;
+        });
         $user = $this->user->findOrFail($id);
         $user->delete();
         return redirect('/users');
diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php
index 9be234e3f..9f3444c88 100644
--- a/app/Http/Kernel.php
+++ b/app/Http/Kernel.php
@@ -26,8 +26,9 @@ class Kernel extends HttpKernel
      * @var array
      */
     protected $routeMiddleware = [
-        'auth' => \Oxbow\Http\Middleware\Authenticate::class,
+        'auth'       => \Oxbow\Http\Middleware\Authenticate::class,
         'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
-        'guest' => \Oxbow\Http\Middleware\RedirectIfAuthenticated::class,
+        'guest'      => \Oxbow\Http\Middleware\RedirectIfAuthenticated::class,
+        'perm'       => \Oxbow\Http\Middleware\PermissionMiddleware::class
     ];
 }
diff --git a/app/Http/Middleware/PermissionMiddleware.php b/app/Http/Middleware/PermissionMiddleware.php
new file mode 100644
index 000000000..c832aeabc
--- /dev/null
+++ b/app/Http/Middleware/PermissionMiddleware.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Oxbow\Http\Middleware;
+
+use Closure;
+use Illuminate\Support\Facades\Session;
+
+class PermissionMiddleware
+{
+    /**
+     * Handle an incoming request.
+     *
+     * @param  \Illuminate\Http\Request $request
+     * @param  \Closure                 $next
+     * @param                           $permission
+     * @return mixed
+     */
+    public function handle($request, Closure $next, $permission)
+    {
+
+        if (!$request->user() || !$request->user()->can($permission)) {
+            Session::flash('error', trans('errors.permission'));
+            return redirect()->back();
+        }
+
+        return $next($request);
+    }
+}
diff --git a/app/Http/routes.php b/app/Http/routes.php
index 4811b74d0..63b0d5262 100644
--- a/app/Http/routes.php
+++ b/app/Http/routes.php
@@ -11,12 +11,14 @@
 |
 */
 
-
+Route::get('/test', function () {
+    return Auth::user()->can('users-edit');
+});
 
 // Authentication routes...
-Route::group(['middleware' => 'auth'], function() {
+Route::group(['middleware' => 'auth'], function () {
 
-    Route::group(['prefix' => 'books'], function() {
+    Route::group(['prefix' => 'books'], function () {
 
         // Books
         Route::get('/', 'BookController@index');
diff --git a/app/Permission.php b/app/Permission.php
new file mode 100644
index 000000000..44776901f
--- /dev/null
+++ b/app/Permission.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace Oxbow;
+
+use Illuminate\Database\Eloquent\Model;
+
+class Permission extends Model
+{
+    /**
+     * The roles that belong to the permission.
+     */
+    public function roles()
+    {
+        return $this->belongsToMany('Oxbow\Permissions');
+    }
+}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index 51e205b79..5be29756d 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -2,7 +2,9 @@
 
 namespace Oxbow\Providers;
 
+use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\ServiceProvider;
+use Oxbow\User;
 
 class AppServiceProvider extends ServiceProvider
 {
diff --git a/app/Role.php b/app/Role.php
new file mode 100644
index 000000000..dd955863e
--- /dev/null
+++ b/app/Role.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Oxbow;
+
+use Illuminate\Database\Eloquent\Model;
+
+class Role extends Model
+{
+    /**
+     * The roles that belong to the role.
+     */
+    public function users()
+    {
+        return $this->belongsToMany('Oxbow\User');
+    }
+
+    /**
+     * The permissions that belong to the role.
+     */
+    public function permissions()
+    {
+        return $this->belongsToMany('Oxbow\Permission');
+    }
+
+    /**
+     * Add a permission to this role.
+     * @param Permission $permission
+     */
+    public function attachPermission(Permission $permission)
+    {
+        $this->permissions()->attach($permission->id);
+    }
+
+}
diff --git a/app/User.php b/app/User.php
index c7f547aad..d58ded82e 100644
--- a/app/User.php
+++ b/app/User.php
@@ -40,13 +40,63 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
     {
         return new static([
             'email' => 'guest',
-            'name' => 'Guest'
+            'name'  => 'Guest'
         ]);
     }
 
+    /**
+     * Permissions and roles
+     */
+
+    /**
+     * The roles that belong to the user.
+     */
+    public function roles()
+    {
+        return $this->belongsToMany('Oxbow\Role');
+    }
+
+    public function getRoleAttribute()
+    {
+        return $this->roles()->first();
+    }
+
+    /**
+     * Check if the user has a particular permission.
+     * @param $permissionName
+     * @return bool
+     */
+    public function can($permissionName)
+    {
+        $permissions = $this->role->permissions()->get();
+        $permissionSearch = $permissions->search(function ($item, $key) use ($permissionName) {
+            return $item->name == $permissionName;
+        });
+        return $permissionSearch !== false;
+    }
+
+    /**
+     * Attach a role to this user.
+     * @param Role $role
+     */
+    public function attachRole(Role $role)
+    {
+        $this->attachRoleId($role->id);
+    }
+
+    /**
+     * Attach a role id to this user.
+     * @param $id
+     */
+    public function attachRoleId($id)
+    {
+        $this->roles()->sync([$id]);
+    }
+
     /**
      * Returns the user's avatar,
      * Uses Gravatar as the avatar service.
+     *
      * @param int $size
      * @return string
      */
diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php
index 65d3d0838..68a2940a4 100644
--- a/database/migrations/2014_10_12_000000_create_users_table.php
+++ b/database/migrations/2014_10_12_000000_create_users_table.php
@@ -20,6 +20,12 @@ class CreateUsersTable extends Migration
             $table->rememberToken();
             $table->timestamps();
         });
+
+        \Oxbow\User::create([
+            'name' => 'Admin',
+            'email' => 'admin@admin.com',
+            'password' => \Illuminate\Support\Facades\Hash::make('password')
+        ]);
     }
 
     /**
diff --git a/database/migrations/2015_08_29_105422_add_roles_and_permissions.php b/database/migrations/2015_08_29_105422_add_roles_and_permissions.php
new file mode 100644
index 000000000..1f7f6126d
--- /dev/null
+++ b/database/migrations/2015_08_29_105422_add_roles_and_permissions.php
@@ -0,0 +1,137 @@
+<?php
+
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+/**
+ * Much of this code has been taken from entrust,
+ * a role & permission management solution for Laravel.
+ *
+ * Full attribution of the database Schema shown below goes to the entrust project.
+ *
+ * @license MIT
+ * @package Zizaco\Entrust
+ * @url https://github.com/Zizaco/entrust
+ */
+class AddRolesAndPermissions extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        // Create table for storing roles
+        Schema::create('roles', function (Blueprint $table) {
+            $table->increments('id');
+            $table->string('name')->unique();
+            $table->string('display_name')->nullable();
+            $table->string('description')->nullable();
+            $table->timestamps();
+        });
+
+        // Create table for associating roles to users (Many-to-Many)
+        Schema::create('role_user', function (Blueprint $table) {
+            $table->integer('user_id')->unsigned();
+            $table->integer('role_id')->unsigned();
+
+            $table->foreign('user_id')->references('id')->on('users')
+                ->onUpdate('cascade')->onDelete('cascade');
+            $table->foreign('role_id')->references('id')->on('roles')
+                ->onUpdate('cascade')->onDelete('cascade');
+
+            $table->primary(['user_id', 'role_id']);
+        });
+
+        // Create table for storing permissions
+        Schema::create('permissions', function (Blueprint $table) {
+            $table->increments('id');
+            $table->string('name')->unique();
+            $table->string('display_name')->nullable();
+            $table->string('description')->nullable();
+            $table->timestamps();
+        });
+
+        // Create table for associating permissions to roles (Many-to-Many)
+        Schema::create('permission_role', function (Blueprint $table) {
+            $table->integer('permission_id')->unsigned();
+            $table->integer('role_id')->unsigned();
+
+            $table->foreign('permission_id')->references('id')->on('permissions')
+                ->onUpdate('cascade')->onDelete('cascade');
+            $table->foreign('role_id')->references('id')->on('roles')
+                ->onUpdate('cascade')->onDelete('cascade');
+
+            $table->primary(['permission_id', 'role_id']);
+        });
+
+
+        // Create default roles
+        $admin = new \Oxbow\Role();
+        $admin->name = 'admin';
+        $admin->display_name = 'Admin';
+        $admin->description = 'Administrator of the whole application';
+        $admin->save();
+
+        $editor = new \Oxbow\Role();
+        $editor->name = 'editor';
+        $editor->display_name = 'Editor';
+        $editor->description = 'User can edit Books, Chapters & Pages';
+        $editor->save();
+
+        $viewer = new \Oxbow\Role();
+        $viewer->name = 'viewer';
+        $viewer->display_name = 'Viewer';
+        $viewer->description = 'User can view books & their content behind authentication';
+        $viewer->save();
+
+        // Create default CRUD permissions and allocate to admins and editors
+        $entities = ['Book', 'Page', 'Chapter', 'Image'];
+        $ops = ['Create', 'Update', 'Delete'];
+        foreach ($entities as $entity) {
+            foreach ($ops as $op) {
+                $newPermission = new \Oxbow\Permission();
+                $newPermission->name = strtolower($entity) . '-' . strtolower($op);
+                $newPermission->display_name = $op . ' ' . $entity . 's';
+                $newPermission->save();
+                $admin->attachPermission($newPermission);
+                $editor->attachPermission($newPermission);
+            }
+        }
+
+        // Create admin permissions
+        $entities = ['Settings', 'User'];
+        $ops = ['Create', 'Update', 'Delete'];
+        foreach ($entities as $entity) {
+            foreach ($ops as $op) {
+                $newPermission = new \Oxbow\Permission();
+                $newPermission->name = strtolower($entity) . '-' . strtolower($op);
+                $newPermission->display_name = $op . ' ' . $entity;
+                $newPermission->save();
+                $admin->attachPermission($newPermission);
+            }
+        }
+
+        // Set all current users as admins
+        // (At this point only the initially create user should be an admin)
+        $users = \Oxbow\User::all();
+        foreach ($users as $user) {
+            $user->attachRole($admin);
+        }
+
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('permission_role');
+        Schema::drop('permissions');
+        Schema::drop('role_user');
+        Schema::drop('roles');
+    }
+}
diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php
index 633b5e736..988ea2100 100644
--- a/database/seeds/DatabaseSeeder.php
+++ b/database/seeds/DatabaseSeeder.php
@@ -15,11 +15,6 @@ class DatabaseSeeder extends Seeder
         Model::unguard();
 
         // $this->call(UserTableSeeder::class);
-        \Oxbow\User::create([
-            'name' => 'Admin',
-            'email' => 'admin@admin.com',
-            'password' => \Illuminate\Support\Facades\Hash::make('password')
-        ]);
 
         Model::reguard();
     }
diff --git a/resources/assets/sass/_blocks.scss b/resources/assets/sass/_blocks.scss
index 9ebae47c1..bf23eb565 100644
--- a/resources/assets/sass/_blocks.scss
+++ b/resources/assets/sass/_blocks.scss
@@ -60,6 +60,11 @@
   &.large {
     padding: $-xl;
   }
+  >h1, >h2, >h3, >h4 {
+    &:first-child {
+      margin-top: 0.1em;
+    }
+  }
 }
 .padded-vertical, .padded-top {
   padding-top: $-m;
@@ -67,6 +72,7 @@
     padding-top: $-xl;
   }
 }
+
 .padded-vertical, .padded-bottom {
   padding-bottom: $-m;
   &.large {
diff --git a/resources/assets/sass/_text.scss b/resources/assets/sass/_text.scss
index 3f236a9eb..8d7950e2c 100644
--- a/resources/assets/sass/_text.scss
+++ b/resources/assets/sass/_text.scss
@@ -197,7 +197,7 @@ p.secondary, p .secondary, span.secondary, .text-secondary {
  */
 ul {
   list-style: disc;
-  margin-left: $-m;
+  margin-left: $-m*1.5;
 }
 
 /*
diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php
new file mode 100644
index 000000000..53785b684
--- /dev/null
+++ b/resources/lang/en/errors.php
@@ -0,0 +1,11 @@
+<?php
+
+return [
+
+    /**
+     * Error text strings.
+     */
+
+    // Pages
+    'permission' => 'You do not have permission to access the requested page.',
+];
\ No newline at end of file
diff --git a/resources/views/form/model-select.blade.php b/resources/views/form/model-select.blade.php
new file mode 100644
index 000000000..19b4ccecd
--- /dev/null
+++ b/resources/views/form/model-select.blade.php
@@ -0,0 +1,15 @@
+
+<select id="{{ $name }}" name="{{ $name }}">
+    @foreach($options as $option)
+        <option value="{{$option->id}}"
+                @if($errors->has($name)) class="neg" @endif
+                @if(isset($model) || old($name)) @if(old($name) && old($name) === $option->id) selected @elseif(isset($model) && $model->id === $option->id) selected @endif @endif
+                >
+            {{ $option->$displayKey }}
+        </option>
+    @endforeach
+</select>
+
+@if($errors->has($name))
+    <div class="text-neg text-small">{{ $errors->first($name) }}</div>
+@endif
\ No newline at end of file
diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php
index 1e23a1c3b..cb56ad905 100644
--- a/resources/views/users/edit.blade.php
+++ b/resources/views/users/edit.blade.php
@@ -14,6 +14,7 @@
 
     <div class="row">
         <div class="page-content">
+
             <div class="row">
                 <div class="col-md-6">
                     <h1>Edit User</h1>
@@ -33,6 +34,24 @@
                     </div>
                 </div>
             </div>
+
+            <hr class="margin-top large">
+
+            <div class="row">
+                <div class="col-md-12">
+                    <h3>Permissions</h3>
+                    <p>User Role: <strong>{{$user->role->display_name}}</strong>.</p>
+                    <ul class="text-muted">
+                        @foreach($user->role->permissions as $permission)
+                            <li>
+                                {{ $permission->display_name }}
+                            </li>
+                        @endforeach
+                    </ul>
+
+                </div>
+            </div>
+
         </div>
     </div>
 
diff --git a/resources/views/users/form.blade.php b/resources/views/users/form.blade.php
index 5d5aa140c..f3896f2e8 100644
--- a/resources/views/users/form.blade.php
+++ b/resources/views/users/form.blade.php
@@ -1,4 +1,3 @@
-
 <div class="form-group">
     <label for="name">Name</label>
     @include('form/text', ['name' => 'name'])
@@ -10,11 +9,18 @@
 </div>
 
 @if(isset($model))
-<div class="form-group">
+    <div class="form-group">
         <span class="text-muted">
             Only fill the below if you would like <br>to change your password:
         </span>
-</div>
+    </div>
+@endif
+
+@if($currentUser->can('user-update'))
+    <div class="form-group">
+        <label for="role">User Role</label>
+        @include('form/model-select', ['name' => 'role', 'options' => \Oxbow\Role::all(), 'displayKey' => 'display_name'])
+    </div>
 @endif
 
 <div class="form-group">
diff --git a/resources/views/users/index.blade.php b/resources/views/users/index.blade.php
index 2fd51decd..730ead8aa 100644
--- a/resources/views/users/index.blade.php
+++ b/resources/views/users/index.blade.php
@@ -8,7 +8,9 @@
         <div class="col-md-6"></div>
         <div class="col-md-6 faded">
             <div class="action-buttons">
-                <a href="/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>New User</a>
+                @if($currentUser->can('user-create'))
+                    <a href="/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>New User</a>
+                @endif
             </div>
         </div>
     </div>
@@ -21,12 +23,22 @@
                 <th></th>
                 <th>Name</th>
                 <th>Email</th>
+                <th>User Type</th>
             </tr>
             @foreach($users as $user)
                 <tr>
                     <td style="line-height: 0;"><img class="avatar" src="{{$user->getAvatar(40)}}" alt="{{$user->name}}"></td>
-                    <td><a href="/users/{{$user->id}}">{{$user->name}}</a></td>
+                    <td>
+                        @if($currentUser->can('user-update') || $currentUser->id == $user->id)
+                            <a href="/users/{{$user->id}}">
+                        @endif
+                                {{$user->name}}
+                        @if($currentUser->can('user-update') || $currentUser->id == $user->id)
+                            </a>
+                        @endif
+                    </td>
                     <td>{{$user->email}}</td>
+                    <td>{{ $user->role->display_name }}</td>
                 </tr>
             @endforeach
         </table>