diff --git a/package.json b/package.json
index fac6ba8e2f33f9ce78df906ac24242724284e8d8..0327b45bfe8b99b3a5f3ff1189ce261dc54e373b 100644
--- a/package.json
+++ b/package.json
@@ -49,6 +49,7 @@
     "js-cookie": "2.2.0",
     "jsonlint": "1.6.3",
     "jszip": "3.1.5",
+    "localforage": "^1.7.3",
     "lodash": "^4.17.11",
     "lodash.debounce": "^4.0.8",
     "moment": "^2.24.0",
diff --git a/src/lang/en.js b/src/lang/en.js
index 94e64662d14c7e2e696f3e88135d83e7de27b4bf..e21edbce5b54982d4da0d08f89a9618f67940d90 100644
--- a/src/lang/en.js
+++ b/src/lang/en.js
@@ -78,12 +78,15 @@ export default {
   login: {
     title: 'Login Form',
     logIn: 'Log in',
-    username: 'Username@Host',
-    password: 'Password',
+    logInViaPleromaFE: 'Log in via PleromaFE',
+    username: 'username@host',
+    password: 'password',
+    omitHostname: 'omit hostname if Pleroma is located on this domain',
     errorMessage: 'Username must contain username and host, e.g. john@pleroma.social',
     any: 'any',
     thirdparty: 'Or connect with',
-    thirdpartyTips: 'Can not be simulated on local, so please combine you own business simulation! ! !'
+    pleromaFELoginFailed: 'Failed to login via PleromaFE, please login with username/password',
+    pleromaFELoginSucceed: 'Logged in via PleromaFE'
   },
   documentation: {
     documentation: 'Documentation',
diff --git a/src/store/modules/user.js b/src/store/modules/user.js
index 2a81fcb45f58e550f066c3bc2845333d8d1ee3f6..18ff54196742f809b2d49f677bbcb87a121535c1 100644
--- a/src/store/modules/user.js
+++ b/src/store/modules/user.js
@@ -106,6 +106,14 @@ const user = {
         removeAuthHost()
         resolve()
       })
+    },
+    async LoginByPleromaFE({ commit, dispatch }, { token }) {
+      commit('SET_TOKEN', token)
+      setToken(token)
+      commit('SET_AUTH_HOST', window.location.host)
+      setAuthHost(window.location.host)
+
+      dispatch('GetUserInfo')
     }
   }
 }
diff --git a/src/views/login/index.vue b/src/views/login/index.vue
index da396aeabbef194ae66ca2d94ff4cbf924b5c704..fdb00fe21c5d21353986c57c4359dbac35dc806b 100644
--- a/src/views/login/index.vue
+++ b/src/views/login/index.vue
@@ -19,6 +19,7 @@
           auto-complete="on"
         />
       </el-form-item>
+      <div class="omit-host-note">{{ $t('login.omitHostname') }}</div>
 
       <el-form-item prop="password">
         <span class="svg-container">
@@ -37,15 +38,21 @@
         </span>
       </el-form-item>
 
-      <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">
+      <el-button :loading="loading" class="login-button" type="primary" @click.native.prevent="handleLogin">
         {{ $t('login.logIn') }}
       </el-button>
+      <el-button v-if="pleromaFEToken" :loading="loadingPleromaFE" class="login-button" type="primary" @click.native.prevent="handlePleromaFELogin">
+        {{ $t('login.logInViaPleromaFE') }}
+      </el-button>
     </el-form>
   </div>
 </template>
 
 <script>
 import SvgIcon from '@/components/SvgIcon'
+import localforage from 'localforage'
+import _ from 'lodash'
+import i18n from '@/lang'
 
 export default {
   name: 'Login',
@@ -58,8 +65,12 @@ export default {
       },
       passwordType: 'password',
       loading: false,
+      loadingPleromaFE: false,
       showDialog: false,
-      redirect: undefined
+      redirect: undefined,
+      pleromaFEToken: false,
+      pleromaFEStateKey: 'vuex-lz',
+      pleromaFEState: {}
     }
   },
   watch: {
@@ -70,6 +81,16 @@ export default {
       immediate: true
     }
   },
+  async mounted() {
+    const pleromaFEState = await localforage.getItem(this.pleromaFEStateKey)
+    this.pleromaFEState = pleromaFEState
+
+    if (_.get(pleromaFEState, 'oauth.userToken') === undefined) {
+      return
+    }
+
+    this.pleromaFEToken = true
+  },
   methods: {
     showPwd() {
       if (this.passwordType === 'password') {
@@ -88,6 +109,20 @@ export default {
         this.loading = false
       })
     },
+    async handlePleromaFELogin() {
+      this.loadingPleromaFE = true
+      try {
+        await this.$store.dispatch('LoginByPleromaFE', { token: this.pleromaFEState.oauth.userToken })
+      } catch (error) {
+        this.loadingPleromaFE = false
+        this.$message.error(i18n.t('login.pleromaFELoginFailed'))
+      }
+
+      this.loadingPleromaFE = false
+      this.$router.push({ path: this.redirect || '/users/index' })
+
+      this.$message.success(i18n.t('login.pleromaFELoginSucceed'))
+    },
     getLoginData() {
       const [username, authHost] = this.loginForm.username.split('@')
 
@@ -142,6 +177,17 @@ export default {
       border-radius: 5px;
       color: #454545;
     }
+    .login-button {
+      width: 100%;
+      margin: 0 0 10px 0;
+    }
+    .omit-host-note {
+      color: #596f8c;
+      font-size: 0.8em;
+      font-style: italic;
+      margin: -20px 0 15px 0;
+      padding: 3px 0 0 15px;
+    }
   }
 </style>
 
diff --git a/yarn.lock b/yarn.lock
index d6060dd6b1e4ebaf1bea07e19c06e8b65462abe2..a3df3c1405ca30de19003a56b2a5657e2723f877 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6021,7 +6021,7 @@ levn@^0.3.0, levn@~0.3.0:
     prelude-ls "~1.1.2"
     type-check "~0.3.2"
 
-lie@~3.1.0:
+lie@3.1.1, lie@~3.1.0:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e"
   integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=
@@ -6160,6 +6160,13 @@ loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0:
     emojis-list "^2.0.0"
     json5 "^1.0.1"
 
+localforage@^1.7.3:
+  version "1.7.3"
+  resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.7.3.tgz#0082b3ca9734679e1bd534995bdd3b24cf10f204"
+  integrity sha512-1TulyYfc4udS7ECSBT2vwJksWbkwwTX8BzeUIiq8Y07Riy7bDAAnxDaPU/tWyOVmQAcWJIEIFP9lPfBGqVoPgQ==
+  dependencies:
+    lie "3.1.1"
+
 locate-path@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"