diff --git a/api/config/settings/common.py b/api/config/settings/common.py
index 06194348d7e95b37e110479648f864070adcb131..b1283ea86d8a886cab3e98ca962fa7bdc4841c2e 100644
--- a/api/config/settings/common.py
+++ b/api/config/settings/common.py
@@ -1223,6 +1223,7 @@ VERSATILEIMAGEFIELD_RENDITION_KEY_SETS = {
     "attachment_square": [
         ("original", "url"),
         ("medium_square_crop", "crop__200x200"),
+        ("large_square_crop", "crop__600x600"),
     ],
 }
 VERSATILEIMAGEFIELD_SETTINGS = {
diff --git a/api/funkwhale_api/common/models.py b/api/funkwhale_api/common/models.py
index e0bd216198f799d517c7820983ce464d0343ff74..688af540635b0ffebad4c2271a49ba76852da31e 100644
--- a/api/funkwhale_api/common/models.py
+++ b/api/funkwhale_api/common/models.py
@@ -267,6 +267,13 @@ class Attachment(models.Model):
         proxy_url = reverse("api:v1:attachments-proxy", kwargs={"uuid": self.uuid})
         return federation_utils.full_url(proxy_url + "?next=medium_square_crop")
 
+    @property
+    def download_url_large_square_crop(self):
+        if self.file:
+            return utils.media_url(self.file.crop["600x600"].url)
+        proxy_url = reverse("api:v1:attachments-proxy", kwargs={"uuid": self.uuid})
+        return federation_utils.full_url(proxy_url + "?next=large_square_crop")
+
 
 class MutationAttachment(models.Model):
     """
diff --git a/api/funkwhale_api/common/serializers.py b/api/funkwhale_api/common/serializers.py
index 9210c0603c3925d724dc82d79ba5e1c0fae227f8..fa194ea8aa138eb72a27dc62b514b321324d2e2a 100644
--- a/api/funkwhale_api/common/serializers.py
+++ b/api/funkwhale_api/common/serializers.py
@@ -297,6 +297,7 @@ class AttachmentSerializer(serializers.Serializer):
         urls["source"] = o.url
         urls["original"] = o.download_url_original
         urls["medium_square_crop"] = o.download_url_medium_square_crop
+        urls["large_square_crop"] = o.download_url_large_square_crop
         return urls
 
     def create(self, validated_data):
diff --git a/api/funkwhale_api/common/views.py b/api/funkwhale_api/common/views.py
index a4818acd96325c7e069e5646e48cfe25ebc0658c..fe669ad215a7a8f48a877f09c9aff2699989e3a0 100644
--- a/api/funkwhale_api/common/views.py
+++ b/api/funkwhale_api/common/views.py
@@ -175,7 +175,7 @@ class AttachmentViewSet(
             return r
 
         size = request.GET.get("next", "original").lower()
-        if size not in ["original", "medium_square_crop"]:
+        if size not in ["original", "medium_square_crop", "large_square_crop"]:
             size = "original"
 
         try:
diff --git a/api/funkwhale_api/federation/tasks.py b/api/funkwhale_api/federation/tasks.py
index 86bef50e1127a4c26c7ccc92af9b971961f04976..c2bdfad347bc9d35fda9025d18d657c1a4df3ac1 100644
--- a/api/funkwhale_api/federation/tasks.py
+++ b/api/funkwhale_api/federation/tasks.py
@@ -429,7 +429,7 @@ def fetch(fetch_obj):
                 )
             except Exception:
                 logger.exception(
-                    "Error while fetching actor outbox: %s", obj.actor.outbox.url
+                    "Error while fetching actor outbox: %s", obj.actor.outbox_url
                 )
             else:
                 if result.get("next_page"):
diff --git a/api/tests/common/test_serializers.py b/api/tests/common/test_serializers.py
index 1d23efb66140d01231a26745c6df4b84f617574b..e8ef04bca4eb988b84c787505c29b69d6c356d5d 100644
--- a/api/tests/common/test_serializers.py
+++ b/api/tests/common/test_serializers.py
@@ -200,6 +200,9 @@ def test_attachment_serializer_existing_file(factories, to_api_date):
             "medium_square_crop": federation_utils.full_url(
                 attachment.file.crop["200x200"].url
             ),
+            "large_square_crop": federation_utils.full_url(
+                attachment.file.crop["600x600"].url
+            ),
         },
     }
 
@@ -227,6 +230,9 @@ def test_attachment_serializer_remote_file(factories, to_api_date):
             "medium_square_crop": federation_utils.full_url(
                 proxy_url + "?next=medium_square_crop"
             ),
+            "large_square_crop": federation_utils.full_url(
+                proxy_url + "?next=large_square_crop"
+            ),
         },
     }
 
diff --git a/changes/changelog.d/1205.enhancement b/changes/changelog.d/1205.enhancement
new file mode 100644
index 0000000000000000000000000000000000000000..a3ccf4dc37e2915596cb16522b06ea606653f24f
--- /dev/null
+++ b/changes/changelog.d/1205.enhancement
@@ -0,0 +1 @@
+Added a new, large thumbnail size for cover images (#1205
\ No newline at end of file
diff --git a/changes/changelog.d/1210.enhancement b/changes/changelog.d/1210.enhancement
new file mode 100644
index 0000000000000000000000000000000000000000..a41d714e51a337fea53c7a0b0a746a9308328ed7
--- /dev/null
+++ b/changes/changelog.d/1210.enhancement
@@ -0,0 +1 @@
+Enforce authentication when viewing remote channels, profiles and libraries (#1210)
\ No newline at end of file
diff --git a/front/src/components/Queue.vue b/front/src/components/Queue.vue
index bc6979164fa41b088787c658aff20bc40276b5d3..59971c21e5f968b034e9d4391569393b9630119b 100644
--- a/front/src/components/Queue.vue
+++ b/front/src/components/Queue.vue
@@ -6,8 +6,8 @@
           <div class="ui six wide column current-track">
             <div class="ui basic segment" id="player">
               <template v-if="currentTrack">
-                <img ref="cover" alt="" v-if="currentTrack.cover && currentTrack.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.urls.original)">
-                <img ref="cover" alt="" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.urls.original)">
+                <img ref="cover" alt="" v-if="currentTrack.cover && currentTrack.cover.urls.large_square_crop" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.urls.large_square_crop)">
+                <img ref="cover" alt="" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.urls.large_square_crop" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.urls.large_square_crop)">
                 <img class="ui image" alt="" v-else src="../assets/audio/default-cover.png">
                 <h1 class="ui header">
                   <div class="content ellipsis">
diff --git a/front/src/components/library/AlbumDropdown.vue b/front/src/components/library/AlbumDropdown.vue
index 07b7b5a7674fe67243424916b4c79dfbd077f6f9..3cc42f6efb7b7538768022bf0a2d737469ae70f3 100644
--- a/front/src/components/library/AlbumDropdown.vue
+++ b/front/src/components/library/AlbumDropdown.vue
@@ -20,6 +20,15 @@
     <button class="ui floating dropdown circular icon basic button" :title="labels.more" v-dropdown="{direction: 'downward'}">
       <i class="ellipsis vertical icon"></i>
       <div class="menu">
+        <a
+          :href="object.fid"
+          v-if="domain != $store.getters['instance/domain']"
+          target="_blank"
+          class="basic item">
+          <i class="external icon"></i>
+          <translate :translate-params="{domain: domain}" translate-context="Content/*/Button.Label/Verb">View on %{ domain }</translate>
+        </a>
+
         <div
           role="button"
           v-if="isEmbedable"
@@ -86,6 +95,7 @@ import EmbedWizard from "@/components/audio/EmbedWizard"
 import Modal from '@/components/semantic/Modal'
 import ReportMixin from '@/components/mixins/Report'
 
+import {getDomain} from '@/utils'
 
 export default {
   mixins: [ReportMixin],
@@ -108,6 +118,11 @@ export default {
     }
   },
   computed: {
+    domain () {
+      if (this.object) {
+        return getDomain(this.object.fid)
+      }
+    },
     labels() {
       return {
         more: this.$pgettext('*/*/Button.Label/Noun', "More…"),
diff --git a/front/src/components/library/ArtistBase.vue b/front/src/components/library/ArtistBase.vue
index 35b0eb02f662bf4d59efe78c984a0e326ae6e15a..f23b1311ed65b115b2462233b7791ef7b35a0b7b 100644
--- a/front/src/components/library/ArtistBase.vue
+++ b/front/src/components/library/ArtistBase.vue
@@ -57,6 +57,15 @@
               <button class="ui floating dropdown icon button" ref="dropdown" v-dropdown>
                 <i class="dropdown icon"></i>
                 <div class="menu">
+                  <a
+                    :href="object.fid"
+                    v-if="domain != $store.getters['instance/domain']"
+                    target="_blank"
+                    class="basic item">
+                    <i class="external icon"></i>
+                    <translate :translate-params="{domain: domain}" translate-context="Content/*/Button.Label/Verb">View on %{ domain }</translate>
+                  </a>
+
                   <button
                     role="button"
                     v-if="publicLibraries.length > 0"
@@ -137,6 +146,8 @@ import RadioButton from "@/components/radios/Button"
 import TagsList from "@/components/tags/List"
 import ReportMixin from '@/components/mixins/Report'
 
+import {getDomain} from '@/utils'
+
 const FETCH_URL = "albums/"
 
 export default {
@@ -205,6 +216,11 @@ export default {
     }
   },
   computed: {
+    domain () {
+      if (this.object) {
+        return getDomain(this.object.fid)
+      }
+    },
     isPlayable() {
       return (
         this.object.albums.filter(a => {
diff --git a/front/src/components/library/TrackBase.vue b/front/src/components/library/TrackBase.vue
index cf9a93659845098b60d37c7441876b916f970372..18c2ff5e0f476013018415d2cf3316af2ad3dc4c 100644
--- a/front/src/components/library/TrackBase.vue
+++ b/front/src/components/library/TrackBase.vue
@@ -44,6 +44,14 @@
               <button class="ui floating dropdown circular icon basic button" :title="labels.more" v-dropdown="{direction: 'downward'}">
                 <i class="ellipsis vertical icon"></i>
                 <div class="menu" style="right: 0; left: auto">
+                  <a
+                    :href="track.fid"
+                    v-if="domain != $store.getters['instance/domain']"
+                    target="_blank"
+                    class="basic item">
+                    <i class="external icon"></i>
+                    <translate :translate-params="{domain: domain}" translate-context="Content/*/Button.Label/Verb">View on %{ domain }</translate>
+                  </a>
                   <div
                     role="button"
                     v-if="publicLibraries.length > 0"
@@ -116,6 +124,7 @@
 import time from "@/utils/time"
 import axios from "axios"
 import url from "@/utils/url"
+import {getDomain} from '@/utils'
 import logger from "@/logging"
 import PlayButton from "@/components/audio/PlayButton"
 import TrackFavoriteIcon from "@/components/favorites/TrackFavoriteIcon"
@@ -190,6 +199,11 @@ export default {
     }
   },
   computed: {
+    domain () {
+      if (this.track) {
+        return getDomain(this.track.fid)
+      }
+    },
     publicLibraries () {
       return this.libraries.filter(l => {
         return l.privacy_level === 'everyone'
diff --git a/front/src/utils.js b/front/src/utils.js
index fb7117a20aeaca00dba89006aa0afb1493d8caf5..596ec07d53bdd33a11804e8e2345a453cf5ce284 100644
--- a/front/src/utils.js
+++ b/front/src/utils.js
@@ -51,3 +51,9 @@ export function checkRedirectToLogin (store, router) {
     router.push({name: 'login', query: {next: router.currentRoute.fullPath}})
   }
 }
+
+export function getDomain (url) {
+  let parser = document.createElement("a")
+  parser.href = url
+  return parser.hostname
+}
\ No newline at end of file
diff --git a/front/src/views/auth/ProfileBase.vue b/front/src/views/auth/ProfileBase.vue
index 353ab1581c5f7bc5a474b659d5671ece13218730..f776322bf14c1f0590178a774e7812f6d3d46663 100644
--- a/front/src/views/auth/ProfileBase.vue
+++ b/front/src/views/auth/ProfileBase.vue
@@ -9,6 +9,14 @@
           <button class="ui pointing dropdown icon small basic right floated button" ref="dropdown" v-dropdown="{direction: 'downward'}" style="position: absolute; right: 1em; top: 1em;">
             <i class="ellipsis vertical icon"></i>
             <div class="menu">
+              <a
+                :href="object.fid"
+                v-if="object.domain != $store.getters['instance/domain']"
+                target="_blank"
+                class="basic item">
+                <i class="external icon"></i>
+                <translate :translate-params="{domain: object.domain}" translate-context="Content/*/Button.Label/Verb">View on %{ domain }</translate>
+              </a>
               <div
                 role="button"
                 class="basic item"
@@ -93,7 +101,12 @@ export default {
     }
   },
   created() {
-    this.fetch()
+    let authenticated = this.$store.state.auth.authenticated
+    if (!authenticated && this.domain && this.$store.getters['instance/domain'] != this.domain) {
+      this.$router.push({name: 'login', query: {next: this.$route.fullPath}})
+    } else {
+     this.fetch()
+    }
   },
   beforeRouteUpdate (to, from, next) {
     to.meta.preserveScrollPosition = true
diff --git a/front/src/views/channels/DetailBase.vue b/front/src/views/channels/DetailBase.vue
index be8481dafbf6637ca33242e78944f265f1eecf10..7d7dc2143b4779a39cf5256315fad7c3aa04e4d5 100644
--- a/front/src/views/channels/DetailBase.vue
+++ b/front/src/views/channels/DetailBase.vue
@@ -84,6 +84,14 @@
                       <i class="code icon"></i>
                       <translate translate-context="Content/*/Button.Label/Verb">Embed</translate>
                     </a>
+                    <a
+                      :href="object.url"
+                      v-if="object.actor.domain != $store.getters['instance/domain']"
+                      target="_blank"
+                      class="basic item">
+                      <i class="external icon"></i>
+                      <translate :translate-params="{domain: object.actor.domain}" translate-context="Content/*/Button.Label/Verb">View on %{ domain }</translate>
+                    </a>
                     <div class="divider"></div>
                     <a
                       href=""
@@ -270,6 +278,10 @@ export default {
   },
   async created() {
     await this.fetchData()
+    let authenticated = this.$store.state.auth.authenticated
+    if (!authenticated && this.$store.getters['instance/domain'] != this.object.actor.domain) {
+      this.$router.push({name: 'login', query: {next: this.$route.fullPath}})
+    }
   },
   methods: {
     async fetchData() {
diff --git a/front/src/views/library/DetailBase.vue b/front/src/views/library/DetailBase.vue
index a58a179be6a402687806b46fc3a8045736267755..16d2fc56c23b200e45100db1d738f48784fd1b1e 100644
--- a/front/src/views/library/DetailBase.vue
+++ b/front/src/views/library/DetailBase.vue
@@ -7,6 +7,14 @@
           <button class="ui pointing dropdown icon small basic right floated button" ref="dropdown" v-dropdown="{direction: 'downward'}" style="position: absolute; right: 1em; top: 1em;">
             <i class="ellipsis vertical icon"></i>
             <div class="menu">
+              <a
+                :href="object.fid"
+                v-if="object.actor.domain != $store.getters['instance/domain']"
+                target="_blank"
+                class="basic item">
+                <i class="external icon"></i>
+                <translate :translate-params="{domain: object.actor.domain}" translate-context="Content/*/Button.Label/Verb">View on %{ domain }</translate>
+              </a>
               <div
                 role="button"
                 class="basic item"
@@ -148,6 +156,10 @@ export default {
   },
   async created() {
     await this.fetchData()
+    let authenticated = this.$store.state.auth.authenticated
+    if (!authenticated && this.$store.getters['instance/domain'] != this.object.actor.domain) {
+      this.$router.push({name: 'login', query: {next: this.$route.fullPath}})
+    }
   },
   methods: {
     async fetchData() {