diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php
index 03ec2c110..57ca58beb 100644
--- a/app/Http/Controllers/ChapterController.php
+++ b/app/Http/Controllers/ChapterController.php
@@ -117,7 +117,7 @@ class ChapterController extends Controller
         $this->checkOwnablePermission('chapter-update', $chapter);
         $chapter->fill($request->all());
         $chapter->slug = $this->chapterRepo->findSuitableSlug($chapter->name, $book->id, $chapter->id);
-        $chapter->updated_by = auth()->user()->id;
+        $chapter->updated_by = user()->id;
         $chapter->save();
         Activity::add($chapter, 'chapter_update', $book->id);
         return redirect($chapter->getUrl());
diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php
index 43292d941..2dabc417b 100644
--- a/app/Http/Controllers/Controller.php
+++ b/app/Http/Controllers/Controller.php
@@ -33,17 +33,16 @@ abstract class Controller extends BaseController
         $this->middleware(function ($request, $next) {
 
             // Get a user instance for the current user
-            $user = auth()->user();
-            if (!$user) $user = User::getDefault();
-
-            // Share variables with views
-            view()->share('signedIn', auth()->check());
-            view()->share('currentUser', $user);
+            $user = user();
 
             // Share variables with controllers
             $this->currentUser = $user;
             $this->signedIn = auth()->check();
 
+            // Share variables with views
+            view()->share('signedIn', $this->signedIn);
+            view()->share('currentUser', $user);
+
             return $next($request);
         });
     }
diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php
index 4c56516dc..51c5d25bb 100644
--- a/app/Http/Controllers/UserController.php
+++ b/app/Http/Controllers/UserController.php
@@ -57,7 +57,7 @@ class UserController extends Controller
     {
         $this->checkPermission('users-manage');
         $authMethod = config('auth.method');
-        $roles = $this->userRepo->getAssignableRoles();
+        $roles = $this->userRepo->getAllRoles();
         return view('users/create', ['authMethod' => $authMethod, 'roles' => $roles]);
     }
 
@@ -126,12 +126,13 @@ class UserController extends Controller
             return $this->currentUser->id == $id;
         });
 
-        $authMethod = config('auth.method');
-
         $user = $this->user->findOrFail($id);
+
+        $authMethod = ($user->system_name) ? 'system' : config('auth.method');
+
         $activeSocialDrivers = $socialAuthService->getActiveDrivers();
         $this->setPageTitle('User Profile');
-        $roles = $this->userRepo->getAssignableRoles();
+        $roles = $this->userRepo->getAllRoles();
         return view('users/edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]);
     }
 
diff --git a/app/Repos/BookRepo.php b/app/Repos/BookRepo.php
index fdc4dd8d4..1af02035d 100644
--- a/app/Repos/BookRepo.php
+++ b/app/Repos/BookRepo.php
@@ -132,8 +132,8 @@ class BookRepo extends EntityRepo
     {
         $book = $this->book->newInstance($input);
         $book->slug = $this->findSuitableSlug($book->name);
-        $book->created_by = auth()->user()->id;
-        $book->updated_by = auth()->user()->id;
+        $book->created_by = user()->id;
+        $book->updated_by = user()->id;
         $book->save();
         $this->permissionService->buildJointPermissionsForEntity($book);
         return $book;
@@ -149,7 +149,7 @@ class BookRepo extends EntityRepo
     {
         $book->fill($input);
         $book->slug = $this->findSuitableSlug($book->name, $book->id);
-        $book->updated_by = auth()->user()->id;
+        $book->updated_by = user()->id;
         $book->save();
         $this->permissionService->buildJointPermissionsForEntity($book);
         return $book;
diff --git a/app/Repos/ChapterRepo.php b/app/Repos/ChapterRepo.php
index c12a9f0f2..96f5b2d1e 100644
--- a/app/Repos/ChapterRepo.php
+++ b/app/Repos/ChapterRepo.php
@@ -98,8 +98,8 @@ class ChapterRepo extends EntityRepo
     {
         $chapter = $this->chapter->newInstance($input);
         $chapter->slug = $this->findSuitableSlug($chapter->name, $book->id);
-        $chapter->created_by = auth()->user()->id;
-        $chapter->updated_by = auth()->user()->id;
+        $chapter->created_by = user()->id;
+        $chapter->updated_by = user()->id;
         $chapter = $book->chapters()->save($chapter);
         $this->permissionService->buildJointPermissionsForEntity($chapter);
         return $chapter;
diff --git a/app/Repos/EntityRepo.php b/app/Repos/EntityRepo.php
index c94601738..42b0b6b7b 100644
--- a/app/Repos/EntityRepo.php
+++ b/app/Repos/EntityRepo.php
@@ -132,9 +132,8 @@ class EntityRepo
      */
     public function getUserDraftPages($count = 20, $page = 0)
     {
-        $user = auth()->user();
         return $this->page->where('draft', '=', true)
-            ->where('created_by', '=', $user->id)
+            ->where('created_by', '=', user()->id)
             ->orderBy('updated_at', 'desc')
             ->skip($count * $page)->take($count)->get();
     }
diff --git a/app/Repos/PageRepo.php b/app/Repos/PageRepo.php
index 93ff61b62..537dd9bd0 100644
--- a/app/Repos/PageRepo.php
+++ b/app/Repos/PageRepo.php
@@ -148,8 +148,8 @@ class PageRepo extends EntityRepo
     {
         $page = $this->page->newInstance();
         $page->name = 'New Page';
-        $page->created_by = auth()->user()->id;
-        $page->updated_by = auth()->user()->id;
+        $page->created_by = user()->id;
+        $page->updated_by = user()->id;
         $page->draft = true;
 
         if ($chapter) $page->chapter_id = $chapter->id;
@@ -330,7 +330,7 @@ class PageRepo extends EntityRepo
         }
 
         // Update with new details
-        $userId = auth()->user()->id;
+        $userId = user()->id;
         $page->fill($input);
         $page->html = $this->formatHtml($input['html']);
         $page->text = strip_tags($page->html);
@@ -363,7 +363,7 @@ class PageRepo extends EntityRepo
         $page->fill($revision->toArray());
         $page->slug = $this->findSuitableSlug($page->name, $book->id, $page->id);
         $page->text = strip_tags($page->html);
-        $page->updated_by = auth()->user()->id;
+        $page->updated_by = user()->id;
         $page->save();
         return $page;
     }
@@ -381,7 +381,7 @@ class PageRepo extends EntityRepo
         $revision->page_id = $page->id;
         $revision->slug = $page->slug;
         $revision->book_slug = $page->book->slug;
-        $revision->created_by = auth()->user()->id;
+        $revision->created_by = user()->id;
         $revision->created_at = $page->updated_at;
         $revision->type = 'version';
         $revision->summary = $summary;
@@ -404,7 +404,7 @@ class PageRepo extends EntityRepo
      */
     public function saveUpdateDraft(Page $page, $data = [])
     {
-        $userId = auth()->user()->id;
+        $userId = user()->id;
         $drafts = $this->userUpdateDraftsQuery($page, $userId)->get();
 
         if ($drafts->count() > 0) {
@@ -535,7 +535,7 @@ class PageRepo extends EntityRepo
         $query = $this->pageRevision->where('type', '=', 'update_draft')
             ->where('page_id', '=', $page->id)
             ->where('updated_at', '>', $page->updated_at)
-            ->where('created_by', '!=', auth()->user()->id)
+            ->where('created_by', '!=', user()->id)
             ->with('createdBy');
 
         if ($minRange !== null) {
diff --git a/app/Repos/PermissionsRepo.php b/app/Repos/PermissionsRepo.php
index e026d83e8..24497c911 100644
--- a/app/Repos/PermissionsRepo.php
+++ b/app/Repos/PermissionsRepo.php
@@ -35,7 +35,7 @@ class PermissionsRepo
      */
     public function getAllRoles()
     {
-        return $this->role->where('hidden', '=', false)->get();
+        return $this->role->all();
     }
 
     /**
@@ -45,7 +45,7 @@ class PermissionsRepo
      */
     public function getAllRolesExcept(Role $role)
     {
-        return $this->role->where('id', '!=', $role->id)->where('hidden', '=', false)->get();
+        return $this->role->where('id', '!=', $role->id)->get();
     }
 
     /**
@@ -90,8 +90,6 @@ class PermissionsRepo
     {
         $role = $this->role->findOrFail($roleId);
 
-        if ($role->hidden) throw new PermissionsException("Cannot update a hidden role");
-
         $permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : [];
         $this->assignRolePermissions($role, $permissions);
 
diff --git a/app/Repos/UserRepo.php b/app/Repos/UserRepo.php
index 127db9fb5..ab3716fca 100644
--- a/app/Repos/UserRepo.php
+++ b/app/Repos/UserRepo.php
@@ -199,9 +199,9 @@ class UserRepo
      * Get the roles in the system that are assignable to a user.
      * @return mixed
      */
-    public function getAssignableRoles()
+    public function getAllRoles()
     {
-        return $this->role->visible();
+        return $this->role->all();
     }
 
     /**
@@ -211,7 +211,7 @@ class UserRepo
      */
     public function getRestrictableRoles()
     {
-        return $this->role->where('hidden', '=', false)->where('system_name', '=', '')->get();
+        return $this->role->where('system_name', '!=', 'admin')->get();
     }
 
 }
\ No newline at end of file
diff --git a/app/Services/ActivityService.php b/app/Services/ActivityService.php
index f6fea33a1..e41036238 100644
--- a/app/Services/ActivityService.php
+++ b/app/Services/ActivityService.php
@@ -19,7 +19,7 @@ class ActivityService
     {
         $this->activity = $activity;
         $this->permissionService = $permissionService;
-        $this->user = auth()->user();
+        $this->user = user();
     }
 
     /**
diff --git a/app/Services/ImageService.php b/app/Services/ImageService.php
index aa1375487..a56626246 100644
--- a/app/Services/ImageService.php
+++ b/app/Services/ImageService.php
@@ -108,8 +108,8 @@ class ImageService
             'uploaded_to' => $uploadedTo
         ];
 
-        if (auth()->user() && auth()->user()->id !== 0) {
-            $userId = auth()->user()->id;
+        if (user()->id !== 0) {
+            $userId = user()->id;
             $imageDetails['created_by'] = $userId;
             $imageDetails['updated_by'] = $userId;
         }
diff --git a/app/Services/PermissionService.php b/app/Services/PermissionService.php
index 341a69edb..bb78f0b0a 100644
--- a/app/Services/PermissionService.php
+++ b/app/Services/PermissionService.php
@@ -614,7 +614,7 @@ class PermissionService
     private function currentUser()
     {
         if ($this->currentUserModel === false) {
-            $this->currentUserModel = auth()->user() ? auth()->user() : new User();
+            $this->currentUserModel = user();
         }
 
         return $this->currentUserModel;
diff --git a/app/Services/SocialAuthService.php b/app/Services/SocialAuthService.php
index b28a97ea4..d76a7231b 100644
--- a/app/Services/SocialAuthService.php
+++ b/app/Services/SocialAuthService.php
@@ -100,7 +100,7 @@ class SocialAuthService
         $socialAccount = $this->socialAccount->where('driver_id', '=', $socialId)->first();
         $user = $this->userRepo->getByEmail($socialUser->getEmail());
         $isLoggedIn = auth()->check();
-        $currentUser = auth()->user();
+        $currentUser = user();
 
         // When a user is not logged in and a matching SocialAccount exists,
         // Simply log the user into the application.
@@ -214,9 +214,9 @@ class SocialAuthService
     public function detachSocialAccount($socialDriver)
     {
         session();
-        auth()->user()->socialAccounts()->where('driver', '=', $socialDriver)->delete();
+        user()->socialAccounts()->where('driver', '=', $socialDriver)->delete();
         session()->flash('success', title_case($socialDriver) . ' account successfully detached');
-        return redirect(auth()->user()->getEditUrl());
+        return redirect(user()->getEditUrl());
     }
 
 }
\ No newline at end of file
diff --git a/app/Services/ViewService.php b/app/Services/ViewService.php
index aac9831f7..1a9ee5f70 100644
--- a/app/Services/ViewService.php
+++ b/app/Services/ViewService.php
@@ -18,7 +18,7 @@ class ViewService
     public function __construct(View $view, PermissionService $permissionService)
     {
         $this->view = $view;
-        $this->user = auth()->user();
+        $this->user = user();
         $this->permissionService = $permissionService;
     }
 
@@ -84,7 +84,7 @@ class ViewService
             ->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type');
 
         if ($filterModel) $query = $query->where('viewable_type', '=', get_class($filterModel));
-        $query = $query->where('user_id', '=', auth()->user()->id);
+        $query = $query->where('user_id', '=', user()->id);
 
         $viewables = $query->with('viewable')->orderBy('updated_at', 'desc')
             ->skip($count * $page)->take($count)->get()->pluck('viewable');
diff --git a/app/User.php b/app/User.php
index 8c39d81be..09b189cbb 100644
--- a/app/User.php
+++ b/app/User.php
@@ -5,6 +5,7 @@ use Illuminate\Auth\Authenticatable;
 use Illuminate\Auth\Passwords\CanResetPassword;
 use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
 use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 use Illuminate\Notifications\Notifiable;
 
 class User extends Model implements AuthenticatableContract, CanResetPasswordContract
@@ -36,21 +37,30 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
     protected $permissions;
 
     /**
-     * Returns a default guest user.
+     * Returns the default public user.
+     * @return User
      */
     public static function getDefault()
     {
-        return new static([
-            'email' => 'guest',
-            'name' => 'Guest'
-        ]);
+        return static::where('system_name', '=', 'public')->first();
+    }
+
+    /**
+     * Check if the user is the default public user.
+     * @return bool
+     */
+    public function isDefault()
+    {
+        return $this->system_name === 'public';
     }
 
     /**
      * The roles that belong to the user.
+     * @return BelongsToMany
      */
     public function roles()
     {
+        if ($this->id === 0) return ;
         return $this->belongsToMany(Role::class);
     }
 
diff --git a/app/helpers.php b/app/helpers.php
index dd835fbf6..ad1c7dd20 100644
--- a/app/helpers.php
+++ b/app/helpers.php
@@ -36,6 +36,16 @@ function versioned_asset($file = '')
     throw new InvalidArgumentException("File {$file} not defined in asset manifest.");
 }
 
+/**
+ * Helper method to get the current User.
+ * Defaults to public 'Guest' user if not logged in.
+ * @return \BookStack\User
+ */
+function user()
+{
+    return auth()->user() ?: \BookStack\User::getDefault();
+}
+
 /**
  * Check if the current user has a permission.
  * If an ownable element is passed in the jointPermissions are checked against
@@ -47,7 +57,7 @@ function versioned_asset($file = '')
 function userCan($permission, Ownable $ownable = null)
 {
     if ($ownable === null) {
-        return auth()->user() && auth()->user()->can($permission);
+        return user() && user()->can($permission);
     }
 
     // Check permission on ownable item
diff --git a/database/migrations/2016_09_29_101449_remove_hidden_roles.php b/database/migrations/2016_09_29_101449_remove_hidden_roles.php
new file mode 100644
index 000000000..f666cad2c
--- /dev/null
+++ b/database/migrations/2016_09_29_101449_remove_hidden_roles.php
@@ -0,0 +1,66 @@
+<?php
+
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class RemoveHiddenRoles extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        // Remove the hidden property from roles
+        Schema::table('roles', function(Blueprint $table) {
+            $table->dropColumn('hidden');
+        });
+
+        // Add column to mark system users
+        Schema::table('users', function(Blueprint $table) {
+            $table->string('system_name')->nullable()->index();
+        });
+
+        // Insert our new public system user.
+        $publicUserId = DB::table('users')->insertGetId([
+            'email' => 'guest@example.com',
+            'name' => 'Guest',
+            'system_name' => 'public',
+            'email_confirmed' => true,
+            'created_at' => \Carbon\Carbon::now(),
+            'updated_at' => \Carbon\Carbon::now(),
+        ]);
+        
+        // Get the public role
+        $publicRole = DB::table('roles')->where('system_name', '=', 'public')->first();
+
+        // Connect the new public user to the public role
+        DB::table('role_user')->insert([
+            'user_id' => $publicUserId,
+            'role_id' => $publicRole->id
+        ]);
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('roles', function(Blueprint $table) {
+            $table->boolean('hidden')->default(false);
+            $table->index('hidden');
+        });
+
+        DB::table('users')->where('system_name', '=', 'public')->delete();
+
+        Schema::table('users', function(Blueprint $table) {
+            $table->dropColumn('system_name');
+        });
+
+        DB::table('roles')->where('system_name', '=', 'public')->update(['hidden' => true]);
+    }
+}
diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php
index 757729763..ac25eb3b5 100644
--- a/resources/views/settings/index.blade.php
+++ b/resources/views/settings/index.blade.php
@@ -79,7 +79,7 @@
                 <div class="form-group">
                     <label for="setting-registration-role">{{ trans('settings.reg_default_role') }}</label>
                     <select id="setting-registration-role" name="setting-registration-role" @if($errors->has('setting-registration-role')) class="neg" @endif>
-                        @foreach(\BookStack\Role::visible() as $role)
+                        @foreach(\BookStack\Role::all() as $role)
                             <option value="{{$role->id}}" data-role-name="{{ $role->name }}"
                                     @if(setting('registration-role', \BookStack\Role::first()->id) == $role->id) selected @endif
                                     >
diff --git a/resources/views/users/forms/system.blade.php b/resources/views/users/forms/system.blade.php
new file mode 100644
index 000000000..3ee5f6409
--- /dev/null
+++ b/resources/views/users/forms/system.blade.php
@@ -0,0 +1,25 @@
+@if($user->system_name == 'public')
+    <p>This user represents any guest users that visit your instance. It cannot be used for logins but is assigned&nbsp;automatically.</p>
+@endif
+
+<div class="form-group">
+    <label for="name">Name</label>
+    @include('form.text', ['name' => 'name'])
+</div>
+
+<div class="form-group">
+    <label for="email">Email</label>
+    @include('form.text', ['name' => 'email'])
+</div>
+
+@if(userCan('users-manage'))
+    <div class="form-group">
+        <label for="role">User Role</label>
+        @include('form/role-checkboxes', ['name' => 'roles', 'roles' => $roles])
+    </div>
+@endif
+
+<div class="form-group">
+    <a href="{{ baseUrl("/settings/users") }}" class="button muted">Cancel</a>
+    <button class="button pos" type="submit">Save</button>
+</div>