Usernames

From the unofficial Signal Wiki

This article is about the upcoming user-facing Usernames feature. "Username" may also refer to other concepts.

Future
This article or section describes a concept currently in development or in beta.
Behavior may change significantly before release.

Usernames are an upcoming feature that allows you to set a username that others can use to find you on Signal without necessarily knowing your phone number. It should not be confused with the upcoming phone number privacy features—by itself, setting a username will not hide your phone number from others (however, depending on how the onboarding for this feature will be designed, in practice the app may suggest or even default to hiding your phone number). In order to hide your phone number from others, you need to use the aforementioned phone number privacy features.

Usernames can be restored after re-registering.[7]

Privacy[edit | edit source]

  • "Usernames [...] aren’t shared on your profile".[8] This means that while people can use your current username to start a chat with you if they know it at that point, people can't see your past, current, or future usernames.
  • The username itself is not visible to the server at any point.
  • The username hash to UUID / ACI mapping is stored on the server in plain text.
  • Signal apps can not make authenticated requests to the server to look up a user by their username hash[9] or look up a username link handle[10] (such requests will be rejected). In other words, these requests must be unauthenticated, thereby improving privacy, as the Signal server only sees the IP address, Signal version (from the user agent), but does not directly see who is looking up a specific username hash or username link handle. See Usernames#Username links for more details about different kinds of links.

Format[edit | edit source]

Usernames have the following format: nickname.discriminator, e.g. nickname.12345.[11]

Nickname[edit | edit source]

The nickname is set by the user. It:

  • Contains only alphanumeric characters (a-z, A-Z, and 0-9) or underscores (_).[12]
    • Under the hood, Signal uses the lowercase version, however.[13] In other words, a nickname may be displayed as NickName in the UI for you (for example, when you use someone's username link),[14] but is treated as nickname. Usernames with the same normalized (lowercased) nickname can coexist, but they must have different discriminators. For example, NickName.123 and nickname.1234 can be used by two different accounts at the same time, but NickName.12 and nickname.12 can not.
  • Does not start with a number (0-9).
  • Has a minimum length that can be configured remotely using the global.nicknames.min feature flag, but defaults to 3 characters.[15]
  • Has a maximum length that can be configured remotely using the global.nicknames.max feature flag, but defaults to 32 characters.[16]
    • Technically the cryptography-related functions support up to (but not including) 48 characters.[17]

Discriminator[edit | edit source]

The discriminator serves the purpose of making one's username more private and less accidentally discoverable.[18]

  • Contains only numbers (0-9).
  • Can't have leading zeros except for the case where there is only one significant digit.[19]
  • Minimum length of 2 digits (starting from 01).
  • Maximum length of 10 digits.[20] However, the only 10-digit discriminator allowed appears to be 1000000000 (1 000 000 000, 109).[21]

The discriminator was generated randomly by the client (app) and couldn't be chosen by the user directly,[note 2][note 3] but this has now changed and you can choose it yourself. The following section describes the generation process before this change.[22][23]

Generation (old)[edit | edit source]

The process of setting a username (which includes the discriminator generation) looks like this:[24][25]

  1. Once a nickname is provided, the discriminator generator starts with the length of 2 digits.
    • When it generates a discriminator of the initial width (2), rather than generating a number from 10 to 100 (like one might expect for a 2-digit discriminator), it generates from 1 to 100. So the discriminators may be 1- digit as well. Although if the generated discriminator's length is less than the initial width, it is left-padded with zeros, e.g. nickname.01 instead of nickname.1.[26]
  2. It generates 4 random discriminators of the initial length.
  3. Then it increases the discriminator length and generates 3 discriminators. This continues up to (and including) a discriminator of 9 digits.
    • There are a total of 20 discriminators generated. This matches up with the maximum amount of username hashes the server accepts for a given reservation attempt.[27]
    • The number of attempts may change between attempts. See the table in the 2023 section for a visual overview.
  4. The client (app) sends a list of username hashes, all with different discriminators, to the server.
  5. The server checks each username hash one by one to see if it happens to be available. If an available username hash has been found, the username is reserved[28] for the user for a short amount of time (5 minutes)[24] to allow them to confirm that they would like to set a username with the provided discriminator.
    • If an available username hash has not been found, the username is shown as not available to the user.[note 3]
  6. When (if) the user confirms the username, the server validates the associated zero-knowledge proof that the client provides.[29]
    • The proof proves to the server that you know the nickname and discriminator pair that produced the username hash you provided.[30]

Username links[edit | edit source]

There appear to be two distinct link types being developed.

However, it's possible that the new Username link type will replace the previously developed hash-based link, and the server API endpoints used to look up users by their username hash will only be used if you manually type in a username to look up in Signal.

Username link[edit | edit source]

This link is not based on your username. Rather, it will contain a (random) UUID (not the account UUID, ACI, or PNI) called a username link handle[31] that simply points to your encrypted username stored on the server.[32] Since the username is encrypted (by your app before uploading it to the server to activate the link), it is likely the link will also contain a (random) key to decrypt the username (this key does not need to be submitted to the server).

As such, this link can be created, updated, and deleted independently of your username. This means it may be intended for use as a temporary, throwaway link that you can share with someone without revealing your username or its hash directly (it will only be revealed to them once they look it up). When you delete the link, it can no longer be used to look up your encrypted username and hence contact you in any way and is thus rendered completely useless.

You must have a username set up to activate such a link. You can only have one username link active at a time.[32]

Hash-based link[edit | edit source]

This link contains the hash of your username. As such, it can only change if you change your username, and you can only have one such link active at a time.

See the Username-based section of the signal.me URLs article for more details on the URL format of this link.

Development history and timeline[edit | edit source]

Usernames have undergone multiple changes while they were in development. Additionally, some timelines for release have been communicated. Some of these changes and timelines are listed below. Note that this list does not include development of related features such as UUIDs / ACIs / PNIs, phone number privacy.

See also: signal.me URLs#Change history.

2019[edit | edit source]

  • 2019-08-08[33] (or at least as early as 2019-08-15[5]): Development begins, usernames do not have any kind of discriminator.
  • 2019-09-25: A way to reserve (in current terminology, prohibit, as reserving is now a part of the process of setting a username as described in Generation) usernames to be only settable by certain users is implemented.[34]
  • 2019-10-28: Usernames can no longer start with a number.[35]

2022[edit | edit source]

  • 2022-08-15: Support for discriminators is added.[36]
  • 2022-09-07: Approximate timeline of release, "early 2023 at the latest", is communicated.[37]
  • 2022-09-14: Discriminator separator changed from # to .. Initial discriminator width changed from 4 to 2. [38]
    • The change to the separator may have been done in part because, due to the signal.me URL format at that time, the # would be URL-encoded for signal.me links into %23, which would have made it harder to visually discern the discriminator (e.g. https://signal.me/#u/nickname%2312345).
    • The following table shows how the discriminator generation changed due to the initial width change. There will be more chances to get a shorter discriminator (and 20 more attempts to randomly find any available discriminator in general). Note that despite this, the total amount of available discriminators for a given nickname (109 - 1 = 999 999 999) hasn’t changed.
Discriminator generation change #1 overview
Attempts to find available discriminator Previous configuration New configuration
10 nickname#0001 or nickname#0012 or nickname#0123 or nickname#1234 nickname.01 or nickname.12
10 nickname.123
10 nickname.1234
10 nickname#12345 nickname.12345
10 nickname#123456 nickname.123456
10 nickname#1234567 nickname.1234567
10 nickname#12345678 nickname.12345678
10 nickname#123456789 nickname.123456789
  • 2022-10-19: Approximate timeline of release, "first half of 2023", is communicated.[39]
  • 2022-11-10: Based on code, it is expected that usernames will be released together with phone number privacy.[40]
  • 2022-12-13: Usernames are now case-sensitive,[41] but uniqueness checks etc. use the lowercase version.

2023[edit | edit source]

  • 2023-02-012023-02-09: Implementation transitions to username hashes that use zero-knowledge cryptography.[42]
    • Nickname minimum and maximum length is now configured using remote feature flags.[43]
    • The value stored on the server is now the username hash, not the plain text username.
    • Due to this change it's likely no longer possible for the server to prohibit certain nickname patterns (i.e. make them only settable by certain accounts that they have been assigned to),[44] forbid certain discriminators,[45] or create usernames without discriminators through some "out-of-band" mechanism,[46] which was all possible before.
    • Discriminator generation is now performed client-side. (See the updated Generation section.)
    • Discriminator generation attempts[note 4] changed as illustrated by the following table.
Discriminator generation change #2 overview
Patterns Before: attempts to find available discriminator After: "attempts" to find available discriminator[note 4][47]
nickname.01 or nickname.12 10 4
nickname.123 10 3
nickname.1234 10 3
nickname.12345 10 2
nickname.123456 10 2
nickname.1234567 10 2
nickname.12345678 10 2
nickname.123456789 10 2
Total attempts 80 20
  • 2023-04-11: References in the code to prohibited usernames are removed,[48] thus confirming that it's no longer possible for the server to prohibit certain nickname patterns, as mentioned above.
  • 2023-06-02: "Username links" introduced in the server code in addition, or to replace hash-based links.[49] Additionally, more server API documentation was added, and some integration tests were added too.[50] See Usernames#Username links for more details.
  • 2023-10-05: Approximate timeline of release, "early 2024", is communicated.[51]
  • 2023-11-08: Public username testing begins in the staging environment.[52]

2024[edit | edit source]

  • 2024-01-09: You can now pick any custom discriminator in the app (currently, iOS and Android only) and attempt to reserve and claim it if it's available.[22][23]
  • 2024-01-18: The new implementation with zero-knowledge cryptography now makes use of case-sensitive nicknames, but does so just for the username people see when using your username link.[14] Under the hood the username is still lowercase-only and that's what determines its uniqueness.
  • 2024-02-20: Usernames and phone number privacy are now available in beta and are officially announced.

Notes[edit | edit source]

  1. In 6.2.0, no longer used; instead, the feature flag for phone number privacy, android.pnp, decides whether the feature is active github:signalapp/Signal-Android/commit/a2415261bd39092020a7e02b402ad20878808212
  2. However, it may be possible to create a custom build of Signal which would allow choosing a discriminator, or more precisely a set of discriminators (any of which you'd accept) to submit to the server, manually.
  3. 3.0 3.1 It is likely possible to re-attempt the whole process of discriminator generation (in hope of getting a discriminator that's available) by changing the username (and then restoring the previous one) in the input field in the app.
  4. 4.0 4.1 Note that attempts after this change have a slightly different meaning. They now represent the distribution of nicknames submitted by the app to the server all at once, rather than the number of times the server tries to generate each discriminator consecutively. However, as the server appears to check availability of the provided username hashes consecutively, it still can be considered an "attempt".

References[edit | edit source]

  1. forum:t/59024
  2. forum:t/59027
  3. forum:t/59023
  4. github:signalapp/Signal-Android/commit/608815a69b78000345ef39510c71014ccbfd3003
  5. 5.0 5.1 github:signalapp/Signal-iOS/commit/5ce5264d074061080ea0eb7da31f3ae17226c384
  6. github:signalapp/Signal-Desktop/commit/3190f95fac724ab0c1a30cb5b7e0213d918aa25f
  7. "Add support for restoring usernames post-registration."
  8. Signal iOS: Localizable.strings#L7132-L7133
  9. AccountController.java#L828
  10. AccountController.java#L922
  11. UsernameGenerator.java#L24-L36
  12. UsernameUtil.java#L32
  13. libsignal/rust/usernames/src/username.rs#L212-L220: "The mapping is only defined for the characters matching [_0-9a-z]"
  14. 14.0 14.1 "Add support for changing visible username case"
  15. RemoteConfigManager.swift#L252-L255
  16. RemoteConfigManager.swift#L257-L260
  17. libsignal/rust/usernames/src/constants.rs#L36-L37
  18. strings.xml#L1987-L1991
  19. username.rs#L432-L433
  20. UsernameUtil.kt#L12
  21. username.rs#L365C36-L365C49
  22. 22.0 22.1 "Allow for picking a custom username discriminator"
  23. 23.0 23.1 "Add ability to set custom username discriminators."
  24. 24.0 24.1 UsernameConfiguration.java#L14-L27
  25. UsernameGenerator.java#L61-L93
  26. github:signalapp/Signal-Server/commit/1891622e69b10c3b8affe9ded2b97ee1ebc74b9e
  27. AccountController.java#L115
  28. github:signalapp/Signal-Server/commit/4032ddd4fd9c21b32d1c2469d2d93986362b7d5c
  29. AccountController.java#L726-L730
  30. forum:t/9157/889
  31. AccountController.java#L877
  32. 32.0 32.1 /username_link endpoint documentation in AccountController.java#L852-L860
  33. github:signalapp/Signal-Server/commit/99c228dd6dde7029798504c3af32739828ff8c02 (commit on GitHub has the date 2019-11-20, but cloning the repository and looking at the commit yields the timestamp of 2019-08-08 when converted to UTC)
  34. github:signalapp/Signal-Server/commit/523134f24bfd4910616511da50fe769d167bbb60 (commit on GitHub has the date 2019-11-20, but cloning the repository and looking at the commit yields the timestamp of 2019-09-25 when converted to UTC)
  35. github:signalapp/Signal-Server/commit/2b987e6e9301a290648ccc77402172b275083933 (commit on GitHub has the date 2019-11-20, but cloning the repository and looking at the commit yields the timestamp of 2019-10-28 when converted to UTC)
  36. github:signalapp/Signal-Server/commit/a84a7dbc3d7d7a519e3ef9c080c07d97befd4758
  37. [1] via forum:t/9157/624
  38. github:signalapp/Signal-Server/commit/d0a8899daf3f9771bba87a3c1ea527b6c96d8d6b
  39. https://twitter.com/mer__edith/status/1582832959694204933
  40. github:signalapp/Signal-Android/commit/a2415261bd39092020a7e02b402ad20878808212
  41. github:signalapp/Signal-Server/commit/26f5ffdde34ec2941f6c6c1f07be9ee3380d2569
  42. github:signalapp/libsignal/commit/731964f46838c1f26ca1848579b9ee80ffeb14f3
  43. UsernameSelectionViewController.swift#L30-L34
  44. ProhibitedUsernames.java
  45. AccountsManager.java#L357
  46. AccountController.java#L949-L956
  47. libsignal/rust/usernames/src/constants.rs#L49
  48. signalapp/Signal-Server commit 61af1ba02
  49. signalapp/Signal-Server/commit/47cc7fd615fe5d159953190b546e199aac955df9
  50. signalapp/Signal-Server/commit/e6917d8427e272046e70c723c02e60b5c3f63a78
  51. "How do organizations like Signal sustain in an environment of mass surveillance" by Meredith Whittaker (Hasgeek TV). (Credits to post #1276 by QuickBanana in Usernames in Signal, post by u/Strength6092 on Reddit.)
  52. "After rounds of internal testing, we have hit the point where we think the community that powers these forums can help us test even further before public launch."post #1 by jimio in Public Username Testing (Staging Environment)
Cookies help us deliver our services. By using our services, you agree to our use of cookies.