Index: src/routes/activitypub.js
===================================================================
--- src/routes/activitypub.js	(revision bf72108b0805b6f9d9780ea0ffef023a60b86f4d)
+++ src/routes/activitypub.js	(revision 4407c67257b1d061f0376ef1ea63ea597c308e4b)
@@ -84,16 +84,32 @@
 });
 
-// ── Followers (count only) ────────────────────────────────────────
+// ── Followers (count-only public, full for the owner) ─────────────
+// A C2S bearer scoped to this site (the account owner) gets the real actor
+// URIs so their own client can build a friends list; everyone else gets the
+// count only (privacy).
 router.get('/ap/users/:slug/followers', (req, res) => {
-  const site = publicSite(req.params.slug);
-  if (!site) return res.status(404).end();
+  const auth = OAuth.verifyBearer(req.headers.authorization);
+  const owner = auth && auth.site.slug === req.params.slug;
+  const site = owner ? auth.site : publicSite(req.params.slug);
+  if (!site) return res.status(404).end();
+  if (owner) {
+    const items = db.prepare('SELECT actor_uri FROM ap_followers WHERE slug = ? ORDER BY created_at').all(site.slug).map((r) => r.actor_uri);
+    return AP.sendAP(res, AP.buildFollowers(baseUrl(req), site, items.length, items));
+  }
   const n = db.prepare('SELECT COUNT(*) n FROM ap_followers WHERE slug = ?').get(site.slug).n;
   AP.sendAP(res, AP.buildFollowers(baseUrl(req), site, n));
 });
 
-// ── Following (count only) ────────────────────────────────────────
+// ── Following (count-only public, full for the owner) ─────────────
 router.get('/ap/users/:slug/following', (req, res) => {
-  const site = publicSite(req.params.slug);
-  if (!site) return res.status(404).end();
+  const auth = OAuth.verifyBearer(req.headers.authorization);
+  const owner = auth && auth.site.slug === req.params.slug;
+  const site = owner ? auth.site : publicSite(req.params.slug);
+  if (!site) return res.status(404).end();
+  if (owner) {
+    let items = [];
+    try { items = db.prepare("SELECT actor_uri FROM ap_following WHERE slug = ? AND status = 'accepted' ORDER BY created_at").all(site.slug).map((r) => r.actor_uri); } catch { /* table may not exist */ }
+    return AP.sendAP(res, AP.buildFollowing(baseUrl(req), site, items.length, items));
+  }
   let n = 0;
   try { n = db.prepare("SELECT COUNT(*) n FROM ap_following WHERE slug = ? AND status = 'accepted'").get(site.slug).n; } catch { /* table may not exist */ }
Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision bf72108b0805b6f9d9780ea0ffef023a60b86f4d)
+++ src/services/ActivityPubService.js	(revision 4407c67257b1d061f0376ef1ea63ea597c308e4b)
@@ -542,5 +542,8 @@
 }
 
-export function buildFollowers(base, site, count) {
+// Public callers get a count-only collection (privacy). The authenticated
+// account owner (a C2S bearer scoped to this site) gets the real actor URIs via
+// `items`, so their own client can build a friends list.
+export function buildFollowers(base, site, count, items = null) {
   const id = `${actorId(base, site.slug)}/followers`;
   return {
@@ -548,6 +551,6 @@
     id,
     type: 'OrderedCollection',
-    totalItems: count || 0,
-    orderedItems: [], // hidden for privacy; count only
+    totalItems: items ? items.length : (count || 0),
+    orderedItems: items || [], // count-only for the public; full for the owner
   };
 }
@@ -555,5 +558,5 @@
 // The accounts this site follows — count only, mirroring buildFollowers. The spec lists
 // `following` as a standard actor property; Hubzilla/Friendica + crawlers expect it.
-export function buildFollowing(base, site, count) {
+export function buildFollowing(base, site, count, items = null) {
   const id = `${actorId(base, site.slug)}/following`;
   return {
@@ -561,6 +564,6 @@
     id,
     type: 'OrderedCollection',
-    totalItems: count || 0,
-    orderedItems: [], // count only
+    totalItems: items ? items.length : (count || 0),
+    orderedItems: items || [], // count-only for the public; full for the owner
   };
 }
