diff --git a/changes/changelog.d/814.enhancement b/changes/changelog.d/814.enhancement
new file mode 100644
index 0000000000000000000000000000000000000000..c93b1983c954bbcec69ee5f3b0f6912d00ed7b5f
--- /dev/null
+++ b/changes/changelog.d/814.enhancement
@@ -0,0 +1 @@
+Added copy-to-clipboard button with Subsonic password input (#814)
diff --git a/front/src/components/auth/SubsonicTokenForm.vue b/front/src/components/auth/SubsonicTokenForm.vue
index 0184074e294365a15e453db7184644d66d75796a..fdd9f5e107b2de27b28cb5099b56751b9be180a6 100644
--- a/front/src/components/auth/SubsonicTokenForm.vue
+++ b/front/src/components/auth/SubsonicTokenForm.vue
@@ -24,7 +24,12 @@
     </div>
     <template v-if="subsonicEnabled">
       <div v-if="token" class="field">
-        <password-input v-model="token" />
+        <password-input
+          ref="passwordInput"
+          v-model="token"
+          :key="token"
+          :copy-button="true"
+          :default-show="showToken"/>
       </div>
       <dangerous-button
         v-if="token"
@@ -69,7 +74,8 @@ export default {
       errors: [],
       success: false,
       isLoading: false,
-      successMessage: ''
+      successMessage: '',
+      showToken: false
     }
   },
   created () {
@@ -98,6 +104,7 @@ export default {
       let self = this
       let url = `users/users/${this.$store.state.auth.username}/subsonic-token/`
       return axios.post(url, {}).then(response => {
+        self.showToken = true
         self.token = response.data['subsonic_api_token']
         self.isLoading = false
         self.success = true
diff --git a/front/src/components/forms/PasswordInput.vue b/front/src/components/forms/PasswordInput.vue
index d57e3017f3010000e6e45932e25e2092982ef246..702be4f66a5642493012afd70ae3ea7d949dd134 100644
--- a/front/src/components/forms/PasswordInput.vue
+++ b/front/src/components/forms/PasswordInput.vue
@@ -10,20 +10,37 @@
     <span @click="showPassword = !showPassword" :title="labels.title" class="ui icon button">
       <i class="eye icon"></i>
     </span>
+    <button v-if="copyButton" @click.prevent="copy" class="ui icon button" :title="labels.copy">
+      <i class="copy icon"></i>
+    </button>
   </div>
 </template>
 <script>
+
+function copyStringToClipboard (str) {
+  // cf https://techoverflow.net/2018/03/30/copying-strings-to-the-clipboard-using-pure-javascript/
+  let el = document.createElement('textarea');
+  el.value = str;
+  el.setAttribute('readonly', '');
+  el.style = {position: 'absolute', left: '-9999px'};
+  document.body.appendChild(el);
+  el.select();
+  document.execCommand('copy');
+  document.body.removeChild(el);
+}
+
 export default {
-  props: ['value', 'index'],
+  props: ['value', 'index', 'defaultShow', 'copyButton'],
   data () {
     return {
-      showPassword: false
+      showPassword: this.defaultShow || false,
     }
   },
   computed: {
     labels () {
       return {
-        title: this.$pgettext('Content/Settings/Button.Tooltip/Verb', 'Show/hide password')
+        title: this.$pgettext('Content/Settings/Button.Tooltip/Verb', 'Show/hide password'),
+        copy: this.$pgettext('*/*/Button.Label/Short, Verb', 'Copy')
       }
     },
     passwordInputType () {
@@ -32,6 +49,11 @@ export default {
       }
       return 'password'
     }
+  },
+  methods: {
+    copy () {
+      copyStringToClipboard(this.value)
+    }
   }
 }
 </script>