diff --git a/front/src/auth/index.js b/front/src/auth/index.js
deleted file mode 100644
index 80236942858440d517d2fe80b7bb43c71b3ea7c0..0000000000000000000000000000000000000000
--- a/front/src/auth/index.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import logger from '@/logging'
-import config from '@/config'
-import cache from '@/cache'
-import Vue from 'vue'
-
-import favoriteTracks from '@/favorites/tracks'
-
-// URL and endpoint constants
-const LOGIN_URL = config.API_URL + 'token/'
-const USER_PROFILE_URL = config.API_URL + 'users/users/me/'
-// const SIGNUP_URL = API_URL + 'users/'
-
-let userData = {
-  authenticated: false,
-  username: '',
-  availablePermissions: {},
-  profile: {}
-}
-let auth = {
-
-  // Send a request to the login URL and save the returned JWT
-  login (context, creds, redirect, onError) {
-    return context.$http.post(LOGIN_URL, creds).then(response => {
-      logger.default.info('Successfully logged in as', creds.username)
-      cache.set('token', response.data.token)
-      cache.set('username', creds.username)
-
-      this.user.authenticated = true
-      this.user.username = creds.username
-      this.connect()
-      // Redirect to a specified route
-      if (redirect) {
-        context.$router.push(redirect)
-      }
-    }, response => {
-      logger.default.error('Error while logging in', response.data)
-      if (onError) {
-        onError(response)
-      }
-    })
-  },
-
-  // To log out, we just need to remove the token
-  logout () {
-    cache.clear()
-    this.user.authenticated = false
-    logger.default.info('Log out, goodbye!')
-  },
-
-  checkAuth () {
-    logger.default.info('Checking authentication...')
-    var jwt = this.getAuthToken()
-    var username = cache.get('username')
-    if (jwt) {
-      this.user.authenticated = true
-      this.user.username = username
-      logger.default.info('Logged back in as ' + username)
-      this.connect()
-    } else {
-      logger.default.info('Anonymous user')
-      this.user.authenticated = false
-    }
-  },
-
-  getAuthToken () {
-    return cache.get('token')
-  },
-
-  // The object to be passed as a header for authenticated requests
-  getAuthHeader () {
-    return 'JWT ' + this.getAuthToken()
-  },
-
-  fetchProfile () {
-    let resource = Vue.resource(USER_PROFILE_URL)
-    return resource.get({}).then((response) => {
-      logger.default.info('Successfully fetched user profile')
-      return response.data
-    }, (response) => {
-      logger.default.info('Error while fetching user profile')
-    })
-  },
-  connect () {
-    // called once user has logged in successfully / reauthenticated
-    // e.g. after a page refresh
-    let self = this
-    this.fetchProfile().then(data => {
-      Vue.set(self.user, 'profile', data)
-      Object.keys(data.permissions).forEach(function (key) {
-        // this makes it easier to check for permissions in templates
-        Vue.set(self.user.availablePermissions, key, data.permissions[String(key)].status)
-      })
-    })
-    favoriteTracks.fetch()
-  }
-}
-
-Vue.set(auth, 'user', userData)
-export default auth
diff --git a/front/src/components/Sidebar.vue b/front/src/components/Sidebar.vue
index 9112c258863e2f8c088197ecafba3f1b61744559..d6a2539224afb89412f5488cd1e7b02ade452cdb 100644
--- a/front/src/components/Sidebar.vue
+++ b/front/src/components/Sidebar.vue
@@ -28,8 +28,8 @@
   <div class="tabs">
     <div class="ui bottom attached active tab" data-tab="library">
       <div class="ui inverted vertical fluid menu">
-        <router-link class="item" v-if="auth.user.authenticated" :to="{name: 'profile', params: {username: auth.user.username}}"><i class="user icon"></i> Logged in as {{ auth.user.username }}</router-link>
-        <router-link class="item" v-if="auth.user.authenticated" :to="{name: 'logout'}"><i class="sign out icon"></i> Logout</router-link>
+        <router-link class="item" v-if="$store.state.auth.authenticated" :to="{name: 'profile', params: {username: $store.state.auth.username}}"><i class="user icon"></i> Logged in as {{ $store.state.auth.username }}</router-link>
+        <router-link class="item" v-if="$store.state.auth.authenticated" :to="{name: 'logout'}"><i class="sign out icon"></i> Logout</router-link>
         <router-link class="item" v-else :to="{name: 'login'}"><i class="sign in icon"></i> Login</router-link>
         <router-link class="item" :to="{path: '/library'}"><i class="sound icon"> </i>Browse library</router-link>
         <router-link class="item" :to="{path: '/favorites'}"><i class="heart icon"></i> Favorites</router-link>
@@ -97,7 +97,6 @@ import Player from '@/components/audio/Player'
 import favoriteTracks from '@/favorites/tracks'
 import Logo from '@/components/Logo'
 import SearchBar from '@/components/audio/SearchBar'
-import auth from '@/auth'
 import backend from '@/audio/backend'
 import draggable from 'vuedraggable'
 
@@ -113,7 +112,6 @@ export default {
   },
   data () {
     return {
-      auth: auth,
       backend: backend,
       favoriteTracks
     }
diff --git a/front/src/components/audio/SearchBar.vue b/front/src/components/audio/SearchBar.vue
index 2324c88392f258f95b7915cce04ea1b9166d5e80..386e24a74f677d40fc60d1b536c15793288a5454 100644
--- a/front/src/components/audio/SearchBar.vue
+++ b/front/src/components/audio/SearchBar.vue
@@ -12,7 +12,6 @@
 <script>
 import jQuery from 'jquery'
 import config from '@/config'
-import auth from '@/auth'
 import router from '@/router'
 
 const SEARCH_URL = config.API_URL + 'search?query={query}'
@@ -27,7 +26,7 @@ export default {
       },
       apiSettings: {
         beforeXHR: function (xhrObject) {
-          xhrObject.setRequestHeader('Authorization', auth.getAuthHeader())
+          xhrObject.setRequestHeader('Authorization', this.$store.getters['auth/header'])
           return xhrObject
         },
         onResponse: function (initialResponse) {
diff --git a/front/src/components/audio/Track.vue b/front/src/components/audio/Track.vue
index 77d5ecc32701d7bcf6b52fce5984644a612ba46d..f0e1f14fa70fbb52a85ba5d99ddc7ffdb4e11dbf 100644
--- a/front/src/components/audio/Track.vue
+++ b/front/src/components/audio/Track.vue
@@ -15,7 +15,6 @@
 <script>
 import {mapState} from 'vuex'
 import backend from '@/audio/backend'
-import auth from '@/auth'
 import url from '@/utils/url'
 
 // import logger from '@/logging'
@@ -40,12 +39,12 @@ export default {
         return null
       }
       let path = backend.absoluteUrl(file.path)
-      if (auth.user.authenticated) {
+      if (this.$store.state.auth.authenticated) {
         // we need to send the token directly in url
         // so authentication can be checked by the backend
         // because for audio files we cannot use the regular Authentication
         // header
-        path = url.updateQueryString(path, 'jwt', auth.getAuthToken())
+        path = url.updateQueryString(path, 'jwt', this.$store.state.auth.token)
       }
       return path
     }
diff --git a/front/src/components/audio/track/Table.vue b/front/src/components/audio/track/Table.vue
index efb98e382804ecb2623d4f96f5e6b9935559052b..4932318603e2c3eb2263b0c152e26fade0aa6fc1 100644
--- a/front/src/components/audio/track/Table.vue
+++ b/front/src/components/audio/track/Table.vue
@@ -58,9 +58,9 @@
                   Keep your PRIVATE_TOKEN secret as it gives access to your account.
                 </div>
                 <pre>
-export PRIVATE_TOKEN="{{ auth.getAuthToken ()}}"
+export PRIVATE_TOKEN="{{ $store.state.auth.token ()}}"
 <template v-for="track in tracks"><template v-if="track.files.length > 0">
-curl -G -o "{{ track.files[0].filename }}" <template v-if="auth.user.authenticated">--header "Authorization: JWT $PRIVATE_TOKEN"</template> "{{ backend.absoluteUrl(track.files[0].path) }}"</template></template>
+curl -G -o "{{ track.files[0].filename }}" <template v-if="$store.state.auth.authenticated">--header "Authorization: JWT $PRIVATE_TOKEN"</template> "{{ backend.absoluteUrl(track.files[0].path) }}"</template></template>
 </pre>
               </div>
             </div>
@@ -83,7 +83,6 @@ curl -G -o "{{ track.files[0].filename }}" <template v-if="auth.user.authenticat
 
 <script>
 import backend from '@/audio/backend'
-import auth from '@/auth'
 import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
 import PlayButton from '@/components/audio/PlayButton'
 
@@ -102,7 +101,6 @@ export default {
   data () {
     return {
       backend: backend,
-      auth: auth,
       showDownloadModal: false
     }
   }
diff --git a/front/src/components/auth/Login.vue b/front/src/components/auth/Login.vue
index 54e7b82e096433aacd18d02053e66c164e51ca60..99b439af8b3e25c821ddb1dbc0c86c6419961d2c 100644
--- a/front/src/components/auth/Login.vue
+++ b/front/src/components/auth/Login.vue
@@ -39,12 +39,11 @@
 </template>
 
 <script>
-import auth from '@/auth'
 
 export default {
   name: 'login',
   props: {
-    next: {type: String}
+    next: {type: String, default: '/'}
   },
   data () {
     return {
@@ -72,14 +71,17 @@ export default {
       }
       // We need to pass the component's this context
       // to properly make use of http in the auth service
-      auth.login(this, credentials, {path: this.next}, function (response) {
-        // error callback
-        if (response.status === 400) {
-          self.error = 'invalid_credentials'
-        } else {
-          self.error = 'unknown_error'
+      this.$store.dispatch('auth/login', {
+        credentials,
+        next: this.next,
+        onError: response => {
+          if (response.status === 400) {
+            self.error = 'invalid_credentials'
+          } else {
+            self.error = 'unknown_error'
+          }
         }
-      }).then((response) => {
+      }).then(e => {
         self.isLoading = false
       })
     }
diff --git a/front/src/components/auth/Logout.vue b/front/src/components/auth/Logout.vue
index f4b2979bc05394dc04f7644e88700a08b13989d5..fbacca70338ed295dc284664d443c9b239b25da0 100644
--- a/front/src/components/auth/Logout.vue
+++ b/front/src/components/auth/Logout.vue
@@ -3,8 +3,8 @@
     <div class="ui vertical stripe segment">
       <div class="ui small text container">
         <h2>Are you sure you want to log out?</h2>
-        <p>You are currently logged in as {{ auth.user.username }}</p>
-        <button class="ui button" @click="logout">Yes, log me out!</button>
+        <p>You are currently logged in as {{ $store.state.auth.username }}</p>
+        <button class="ui button" @click="$store.dispatch('auth/logout')">Yes, log me out!</button>
         </form>
       </div>
     </div>
@@ -12,23 +12,8 @@
 </template>
 
 <script>
-import auth from '@/auth'
-
 export default {
-  name: 'logout',
-  data () {
-    return {
-      // We need to initialize the component with any
-      // properties that will be used in it
-      auth: auth
-    }
-  },
-  methods: {
-    logout () {
-      auth.logout()
-      this.$router.push({name: 'index'})
-    }
-  }
+  name: 'logout'
 }
 </script>
 
diff --git a/front/src/components/auth/Profile.vue b/front/src/components/auth/Profile.vue
index 2aaae9e2df34d292f5cc66ae04dee5898bc9d335..607fa8ff2b84ffdde60ccbf3b514938dfeb5aba4 100644
--- a/front/src/components/auth/Profile.vue
+++ b/front/src/components/auth/Profile.vue
@@ -3,17 +3,17 @@
     <div v-if="isLoading" class="ui vertical segment">
       <div :class="['ui', 'centered', 'active', 'inline', 'loader']"></div>
     </div>
-    <template v-if="profile">
+    <template v-if="$store.state.auth.profile">
       <div :class="['ui', 'head', 'vertical', 'center', 'aligned', 'stripe', 'segment']">
         <h2 class="ui center aligned icon header">
           <i class="circular inverted user green icon"></i>
           <div class="content">
-            {{ profile.username }}
+            {{ $store.state.auth.profile.username }}
             <div class="sub header">Registered since {{ signupDate }}</div>
           </div>
         </h2>
         <div class="ui basic green label">this is you!</div>
-        <div v-if="profile.is_staff" class="ui yellow label">
+        <div v-if="$store.state.auth.profile.is_staff" class="ui yellow label">
           <i class="star icon"></i>
           Staff member
         </div>
@@ -23,35 +23,21 @@
 </template>
 
 <script>
-import auth from '@/auth'
-var dateFormat = require('dateformat')
+const dateFormat = require('dateformat')
 
 export default {
   name: 'login',
   props: ['username'],
-  data () {
-    return {
-      profile: null
-    }
-  },
   created () {
-    this.fetchProfile()
-  },
-  methods: {
-    fetchProfile () {
-      let self = this
-      auth.fetchProfile().then(data => {
-        self.profile = data
-      })
-    }
+    this.$store.dispatch('auth/fetchProfile')
   },
   computed: {
     signupDate () {
-      let d = new Date(this.profile.date_joined)
+      let d = new Date(this.$store.state.auth.profile.date_joined)
       return dateFormat(d, 'longDate')
     },
     isLoading () {
-      return !this.profile
+      return !this.$store.state.auth.profile
     }
   }
 }
diff --git a/front/src/components/library/Library.vue b/front/src/components/library/Library.vue
index e8b053b6d0124175fda02254e71a85a420401e5e..3e3de9c61044852d2ae1ba9cb46b5c32a512f3cb 100644
--- a/front/src/components/library/Library.vue
+++ b/front/src/components/library/Library.vue
@@ -4,8 +4,8 @@
       <router-link class="ui item" to="/library" exact>Browse</router-link>
       <router-link class="ui item" to="/library/artists" exact>Artists</router-link>
       <div class="ui secondary right menu">
-        <router-link v-if="auth.user.availablePermissions['import.launch']" class="ui item" to="/library/import/launch" exact>Import</router-link>
-        <router-link v-if="auth.user.availablePermissions['import.launch']" class="ui item" to="/library/import/batches">Import batches</router-link>
+        <router-link v-if="$store.state.auth.availablePermissions['import.launch']" class="ui item" to="/library/import/launch" exact>Import</router-link>
+        <router-link v-if="$store.state.auth.availablePermissions['import.launch']" class="ui item" to="/library/import/batches">Import batches</router-link>
       </div>
     </div>
     <router-view :key="$route.fullPath"></router-view>
@@ -14,15 +14,8 @@
 
 <script>
 
-import auth from '@/auth'
-
 export default {
-  name: 'library',
-  data: function () {
-    return {
-      auth
-    }
-  }
+  name: 'library'
 }
 </script>
 
diff --git a/front/src/components/library/Track.vue b/front/src/components/library/Track.vue
index 36a76e822c2ac0218d8c23a1fb2cca8f21db4f29..48cd801c3d8a96fc34b4904febbacb0d6243d66f 100644
--- a/front/src/components/library/Track.vue
+++ b/front/src/components/library/Track.vue
@@ -61,7 +61,6 @@
 
 <script>
 
-import auth from '@/auth'
 import url from '@/utils/url'
 import logger from '@/logging'
 import backend from '@/audio/backend'
@@ -124,8 +123,8 @@ export default {
     downloadUrl () {
       if (this.track.files.length > 0) {
         let u = backend.absoluteUrl(this.track.files[0].path)
-        if (auth.user.authenticated) {
-          u = url.updateQueryString(u, 'jwt', auth.getAuthToken())
+        if (this.$store.state.auth.authenticated) {
+          u = url.updateQueryString(u, 'jwt', this.$store.state.auth.token)
         }
         return u
       }
diff --git a/front/src/components/metadata/Search.vue b/front/src/components/metadata/Search.vue
index 8a400cf7b0e5b488e794afb62a0ddab8d38ce59a..c3dc7433c5e268baa4e848bcb9a22125b555bd93 100644
--- a/front/src/components/metadata/Search.vue
+++ b/front/src/components/metadata/Search.vue
@@ -23,7 +23,6 @@
 <script>
 import jQuery from 'jquery'
 import config from '@/config'
-import auth from '@/auth'
 
 export default {
   props: {
@@ -66,7 +65,7 @@ export default {
         },
         apiSettings: {
           beforeXHR: function (xhrObject, s) {
-            xhrObject.setRequestHeader('Authorization', auth.getAuthHeader())
+            xhrObject.setRequestHeader('Authorization', this.$store.getters['auth/header'])
             return xhrObject
           },
           onResponse: function (initialResponse) {
diff --git a/front/src/main.js b/front/src/main.js
index eb714976fa4ff46c943e66ca03c0e74496a09583..0c9230e8e8acc3059bf7bf030f53e74e5a69e204 100644
--- a/front/src/main.js
+++ b/front/src/main.js
@@ -9,7 +9,6 @@ import Vue from 'vue'
 import App from './App'
 import router from './router'
 import VueResource from 'vue-resource'
-import auth from './auth'
 import VueLazyload from 'vue-lazyload'
 import store from './store'
 
@@ -26,8 +25,8 @@ Vue.config.productionTip = false
 
 Vue.http.interceptors.push(function (request, next) {
   // modify headers
-  if (auth.user.authenticated) {
-    request.headers.set('Authorization', auth.getAuthHeader())
+  if (store.state.auth.authenticated) {
+    request.headers.set('Authorization', store.getters['auth/header'])
   }
   next(function (response) {
     // redirect to login form when we get unauthorized response from server
@@ -38,7 +37,7 @@ Vue.http.interceptors.push(function (request, next) {
   })
 })
 
-auth.checkAuth()
+store.dispatch('auth/check')
 /* eslint-disable no-new */
 new Vue({
   el: '#app',
diff --git a/front/src/store/auth.js b/front/src/store/auth.js
new file mode 100644
index 0000000000000000000000000000000000000000..851d9c214ba70bfc8831bd4798be2fa01e3c92b7
--- /dev/null
+++ b/front/src/store/auth.js
@@ -0,0 +1,98 @@
+import Vue from 'vue'
+import config from '@/config'
+import logger from '@/logging'
+import cache from '@/cache'
+import router from '@/router'
+// import favoriteTracks from '@/favorites/tracks'
+
+const LOGIN_URL = config.API_URL + 'token/'
+const USER_PROFILE_URL = config.API_URL + 'users/users/me/'
+
+export default {
+  namespaced: true,
+  state: {
+    authenticated: false,
+    username: '',
+    availablePermissions: {},
+    profile: null,
+    token: ''
+  },
+  getters: {
+    header: state => {
+      return 'JWT ' + state.token
+    }
+  },
+  mutations: {
+    profile: (state, value) => {
+      state.profile = value
+    },
+    authenticated: (state, value) => {
+      state.authenticated = value
+    },
+    username: (state, value) => {
+      state.username = value
+    },
+    token: (state, value) => {
+      state.token = value
+    }
+  },
+  actions: {
+    // Send a request to the login URL and save the returned JWT
+    login ({commit, dispatch, state}, {next, credentials, onError}) {
+      let resource = Vue.resource(LOGIN_URL)
+      return resource.save({}, credentials).then(response => {
+        logger.default.info('Successfully logged in as', credentials.username)
+        commit('token', response.data.token)
+        cache.set('token', response.data.token)
+        commit('username', credentials.username)
+        cache.set('username', credentials.username)
+        commit('authenticated', true)
+        dispatch('fetchProfile')
+        // Redirect to a specified route
+        router.push(next)
+      }, response => {
+        logger.default.error('Error while logging in', response.data)
+        onError(response)
+      })
+    },
+    logout ({commit}) {
+      cache.clear()
+      commit('authenticated', false)
+      commit('profile', null)
+      logger.default.info('Log out, goodbye!')
+      router.push({name: 'index'})
+    },
+    check ({commit, dispatch, state}) {
+      logger.default.info('Checking authentication...')
+      var jwt = cache.get('token')
+      var username = cache.get('username')
+      if (jwt) {
+        commit('authenticated', true)
+        commit('username', username)
+        commit('token', jwt)
+        logger.default.info('Logged back in as ' + username)
+        dispatch('fetchProfile')
+      } else {
+        logger.default.info('Anonymous user')
+        commit('authenticated', false)
+      }
+    },
+    fetchProfile ({commit, state}) {
+      let resource = Vue.resource(USER_PROFILE_URL)
+      return resource.get({}).then((response) => {
+        logger.default.info('Successfully fetched user profile')
+        let data = response.data
+        commit('profile', data)
+        // favoriteTracks.fetch()
+        console.log('AFTER')
+        Object.keys(data.permissions).forEach(function (key) {
+          // this makes it easier to check for permissions in templates
+          state.availablePermissions[key] = data.permissions[String(key)].status
+        })
+        return response.data
+      }, (response) => {
+        logger.default.info('Error while fetching user profile')
+      })
+    }
+  }
+}
diff --git a/front/src/store/index.js b/front/src/store/index.js
index afd6e3f84cd6d53002359f7b496b427fa33540f1..35e50e0304f352315a7134f8370d63757114234f 100644
--- a/front/src/store/index.js
+++ b/front/src/store/index.js
@@ -1,6 +1,7 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
 
+import auth from './auth'
 import queue from './queue'
 import radios from './radios'
 import player from './player'
@@ -9,6 +10,7 @@ Vue.use(Vuex)
 
 export default new Vuex.Store({
   modules: {
+    auth,
     queue,
     radios,
     player