Changeable usernames?

Note that Mastodon does not use “username@domain” as a primary key. I’m not sure what Claire meant by a “primary identifier”, but it’s (probably) not that.

Some of the Mastodon accounts indices:

    "accounts_pkey" PRIMARY KEY, btree (id)
...
    "index_accounts_on_username_and_domain_lower" UNIQUE, btree (lower(username::text), COALESCE(lower(domain::text), ''::text))

As the primary key, the id column will also have uniqueness constraints. Again, I don’t know what Claire meant by the username/account columns being the only ones with uniqueness constraints.

In any case, it’s a good point about the problem with usernames being used in AP URIs (which I assume are the “protocol identifiers” described in the issue).

I understand the desire to do this, but I kinda feel like it’s a bad idea. There’s a reason so many existing social media sites don’t allow changing usernames or at least makes it cumbersome. It adds a lot of complexity.

What about all the mentions of the user previously in any posts anywhere on remote servers? Would they somehow have to be updated? That seems ludicrous. Breaking the mentions seems equally bad. The simplest solution is not allowing usernames to change.

Is this really a problem? Email has existed for ages and is also based on this idea - usernames do not change and your identifier is username@domain.example. Honestly I feel that using the username+domain as the unique identifier is much better than using some random numeric ID.

It’s already problematic enough that the ID is not only username+domain, but actually https://domain.example/some/path/username. This makes it very difficult to switch underlying server implementation, as the paths used for ActivityPub IDs may not be the same across servers. I wish ActivityPub had either excluded the paths somehow or standardized the paths under the /.well-known path perhaps.

The more I learn about ActivityPub, the more I am sad that it is as complex as it is - I feel this would only add more complexity.

2 Likes

The thing with mentions is that you parse and rewrite them anyway, so you could as well stash your internal ID for that user somewhere in there and substitute the correct URL upon display. I do that in Smithereen.

Let’s take a random post that has a mention in it. Here’s the text as returned by Mastodon:

<p><span class="h-card" translate="no"><a href="https://hachyderm.io/@samhenrigold" class="u-url mention">@<span>samhenrigold</span></a></span> Looks awesome! I dig the layout.</p>

Here’s how it’s stored in my database:

<p><a href="https://hachyderm.io/@samhenrigold" class="u-url mention" data-user-id="1332">@samhenrigold</a> Looks awesome! I dig the layout.</p>

Here’s what it turns into for display:

<p><span class="h-card hoverCardContainer"><a href="/samhenrigold@hachyderm.io" class="u-url mention hoverCardTrigger" data-user-id="1332" rel="nofollow">@samhenrigold</a></span> Looks awesome! I dig the layout.</p>

What I’m saying is that from Smithereen’s perspective, usernames are purely decorative. The only requirement is that they must be unique. In fact, I even stopped requiring a username for signup in May. As for mentions, when someone changes their username, the text of the link will be the old username (obviously), but it would still link to the right user because I substitute the href to my own internal URL upon display anyway.

There’s nothing in ActivityPub that requires the use of the username as part of the fundamentally unchangeable actor ID. Mastodon does it, Pleroma does it too. Misskey doesn’t do it, and neither does Smithereen. My actor IDs simply use the numeric identifier straight from the database row, they are of the form https://example.social/users/123. The only two places where the username appears in my actors is preferredUsername (obviously) and url. Both these fields can be updated without much trouble.

Well this is kinda what I’m talking about. Who’s to say I parse and rewrite mentions? Maybe I leave that job to the client, or maybe my implementation doesn’t handle mentions at all. Handling it server-side seems like a lot of complexity. If usernames are immutable, I don’t need to worry about that.

But mentions was just one example. There’s also the problem of URLs - what if someone somewhere on the internet links to a user like https://domain.example/users/<username>? That link will break, no? Unless you handle the additional complexity of remembering all past names that a user has had and issue redirects to their current name. Again, complexity and extra work.

Maybe you avoid this by using https://domain.example/users/<opaque ID> but then your URLs are much harder to remember, read and write for human beings, so that’s kinda bad UX. People like having their username in URLs.

Fundamentally, the human perspective also just goes against this idea I feel. Users are used to usernames being static. It’s a common thing across many social media apps (for good reasons) and has always been the case for email. Human beings do not remember users via some numeric ID - they remember users by a username and the platform they are on, i.e. username@domain.example, like an email. So the biggest issue might be that by changing a username, you are breaking the links inside people’s heads and I think you will have a very hard time rewriting those.

I know that ActivityPub doesn’t require the username to be immutable - however, I see this as a mistake. I think Mastodon’s approach of considering username+domain as the primary identifier to be simpler and better overall.

On a more general note, I fear that ActivityPub is too complex for its own good. I realize that it tries to be extremely general to all kinds of social activity that you may do on the internet, but I can’t help but wonder if it was not possible to achieve most of this flexibility with only a fraction of the associated complexity. Simplicity should be a virtue in such a protocol I feel. KISS principle and all that.

1 Like

To be completely frank about this position: if you’re arguing for simplicity, you’re arguing for a more opinionated protocol. A more opinionated protocol will not work neatly most use cases and that would be arguably worse for developer uptake overall.

Maybe, maybe not. I’m not an expert but to me it seems like ActivityPub could be simpler while preserving all or at least most of the flexibility. A simpler protocol would be much easier for developers to pick up.

To be fair, maybe most of my gripes are with the ActivityStreams vocabulary being quite redundant (Article vs Document vs Note vs Page? Service vs Application?). A lot of it just seems bloated and feels like it could be boiled down to fewer, more general categories. I’m also not a fan of using JSON-LD and IDs as URLs (feels like a job for UUIDs).

Anyways, I digress. I actually thought about this some more and I’m really conflicted. On second review, a lot of social media websites these days actually do allow changing usernames (even though email obviously doesn’t). The Activity Vocabulary has this to say on mentions btw (non-normative, but still):

Many social software systems use special text-based microsyntaxes that allow users to define special addressing for notifications, linking, or categorization within objects. For example, including text such as “@username” within an object’s content will often route the object to a special “mentions” or “inbox” stream for a particular user. Likewise, including text such as " #topic" within the object’s content will often mark the object as being related to the topic “topic”. Such mechanisms are commonly referred to as “mentions” and “hashtags”, respectively.

While such microsyntaxes MAY be used within the values of the content, name, and summary properties on an Activity Streams Object, implementations SHOULD NOT be required to parse the values of those properties in order to determine the appropriate routing of notifications, categorization or linking between objects. Instead, publishers SHOULD make appropriate use of the vocabulary terms provided specifically for these purposes.

So you should not be required to parse content in order to find mentions and possibly replace them with unique, immutable IDs. But I’m still kinda curious how you are supposed to change mentions when usernames change then.

If usernames were changable, maybe the simplest thing would be to remember all past usernames of a user and do redirects when the user is mentioned and you click on a mention? The old username may still appear, but you’d be redirected to the new users page. I’m still not fully convinced but maybe leaving the door open to usernames changing by using opaque IDs for AP IDs is still the best idea.

Well yes, links will break. That’s what a username change does. That’s the point. Past usernames will not be remembered and someone else can take your past username.

All mainstream social media services (Twitter, Instagram, Facebook, VKontakte) support doing it and all of them do it more or less like I said — you change your username, mentions of you still link to your profile (with now wrong username), past links break, and anyone else can take your previous username. Why should the fediverse be any different?

For VKontakte in particular though, I’ve seen people assign their previous username to a group (they share a namespace, both are just https://vk.com/xxxx) that contains a single post saying “I’ve now moved to <link to the new username>”.

1 Like

Isn’t this kind of problematic, from a safety/security point of view? Let’s say “A” changes her username to “B”. Then another person makes a new user called “A”. URLs and such that previously linked to the first user’s “A” profile now link to the second user’s “A” profile. So if you’re not aware of the name change, you might think they are the same person but they are not.

This could potentially be used maliciously as well, no? You could try to impersonate the first user by writing slander from the “A” profile. Or it could work the other way around - maybe you accidentally chose a username that was previously used by a user who was really rude or something, and now people think that was you, but actually that rude user just changed their username a while ago.

This is a fundamental problem with the internet and we haven’t quite solved it yet. This already exists for domains (what if the previous owner of a domain you bought hosted something terrible on it) and for IP addresses/subnets (what if the previous owner of an IP address sent email spam and now the entire internet treats you like you’re radioactive because someone thought that using IPs for something beyond packet routing might be a good idea).

For fediverse, this is somewhat solved with verified links, where you put a link to your fediverse profile on your website and vice versa, and Mastodon sees that and shows a checkmark next to that link on your profile.

1 Like

This whole thing makes me wonder about the role of the “name” and “preferredUsername” properties on persons.

“name”, from Activity Vocabulary:

A simple, human-readable, plain-text name for the object. HTML markup MUST NOT be included. The name MAY be expressed using multiple language-tagged values.

and “preferredUsername”, from ActivityPub:

A short username which may be used to refer to the actor, with no uniqueness guarantees.

Is that to say that the “name” property does have uniqueness guarantees? It just makes me wonder: What is the point of having a “name” and a “preferredUsername” as separate properties if usernames are changable? I was under the impression that the point of having two was that one was mutable and the other is not. But now it seems both are mutable - is the point just that one is unique (on that domain) and the other is not necessarily unique?

The name is entirely unrelated to this. This is the user-visible name. It’s just an arbitrary string that is displayed in the UI and is not meant to be interpreted by software in any way whatsoever. Ideally. I try to split it into first and last names, which works most of the time.

The preferredUsername is the one we’re talking about. The way it works right now, there are uniqueness guarantees in the sense that each username can only exist once per domain. All implementations I know of also include the username in some form in the url, which is the user-visible URL for that account’s profile on the web. Which, again, is distinct from id, which is the immutable actor identifier that isn’t displayed anywhere so it can be user-unfriendly. Some implementations have matching url and id, and this prevents them from having changeable usernames. Some (Mastodon) use different formats (id is https://example.social/users/username, url is https://example.social/@username) but still include the username in the id, so this also prevents them from having changeable usernames. And, finally, others, like Smithereen, don’t include the username in the id, which allows for the username to be changed, because formally, id is the only field in an object that cannot be updated, though in practice there are quite a few others, like type, or attributedTo and addressing (to, cc, etc) in Notes.

So hold on, if I see Alice@domain.example and another user Alice@domain.example, they are not necessarily the same user, even though they have the same preferredUsername on the same domain? That seems very surprising. Is this really intended? Not only can usernames change but usernames are not even unique on the same domain?

How are users supposed to tell other users apart when they have the same username on the same domain? How does WebFinger discovery work in this case? I mean which Alice does acct:Alice@domain.example refer to? It seems impossible to use WebFinger in this case.

No. In all real-world ActivityPub implementations, it is enforced that username@domain is globally unique.

I did not say that. The spec may imply it, but as I said, there’s the spec, and then there are the real-world implementations.

It seems kinda worrying that the spec allows this though. To be compliant, I would need to allow for the possibility of a (username, domain) duplicate pair by some ActivityPub implementation in the future which does allow for duplicate usernames on their own server.
Anyways, I guess that is very theoretical. Still though, I’m surprised the spec doesn’t specify that there is a uniqueness guarantee here.

mentions are just a type of link. links can and do break. this is inherent to the web itself.

to put forward an example you may have not considered: implementations like hubzilla and streams encode mentions using the display name and not the username. a mention from those softwares looks like @infinite love and maps that something like this:

{
“type”: “Mention”,
“name”: “@infinite love”,
“href”: “https://trwnh.com”
}

now of course display names can and do change, and in some cases very frequently! but that’s fine, because it’s just a snapshot in time, a lookup table. the way a microsyntax works is entirely local to the current resource. the same way a normal hyperlink works in html — name just represents the a.innerText

1 Like

I also do this in Smithereen when you reply to someone’s comment (because VK does it). Here’s an example:

{
  "type": "Note",
  "id": "https://friends.grishka.me/posts/1362384",
  "attributedTo": "https://friends.grishka.me/users/1",
  "content": "<p><a href=\"https://hachyderm.io/@samhenrigold\" class=\"mention\">sam henri gold</a>, I'm really looking forward to when the 32-bit unixtime overflows. <i>That</i> will sure be a disaster.</p>",
  "inReplyTo": "https://hachyderm.io/users/samhenrigold/statuses/112796506024458736",
  "published": "2024-07-16T14:00:05Z",
  "tag": [
    {
      "type": "Mention",
      "href": "https://hachyderm.io/users/samhenrigold"
    }
  ],
  "url": "https://friends.grishka.me/posts/1362384",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "cc": [
    "https://hachyderm.io/users/samhenrigold"
  ],
  "replies": {
    "type": "Collection",
    "id": "https://friends.grishka.me/posts/1362384/replies",
    "first": {
      "type": "CollectionPage",
      "items": [],
      "partOf": "https://friends.grishka.me/posts/1362384/replies",
      "next": "https://friends.grishka.me/posts/1362384/replies?page=1"
    }
  },
  "sensitive": false,
  "likes": "https://friends.grishka.me/posts/1362384/likes",
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "sensitive": "as:sensitive"
    }
  ]
}

Except Lemmy, where user and community can have the same acct URI. They use additional property to disambiguate two actors in JRD:

https://lemmy.ml/.well-known/webfinger?resource=acct:activitypub@lemmy.ml

2 Likes

Is that to say that the mention breaks if the user behind the mention changes their display name? Or do you mean that you use the lookup table at the time of the mention to find a more permanent link?

no, the mention doesn’t break as long as the href continues to resolve to the same resource

This alone makes the whole idea nonsensical for me. Usernames are fixed, if you want a new one you can delete it and create another account. Its not much effort for the user and means the database remains fully consistent.