Trust and Safety Product/Temporary Accounts/For developers
This page describes some of the technical aspects of Temporary Accounts . It may be useful to people who are updating user scripts, bots and other tools.
Create temporary actor for your features
Features you maintain need updating for the introduction of temporary accounts if they ever create IP actors. They do if:
- Any workflow that leads to an on-wiki log entry including the performer, where the performer might currently be a user whose name is their IP, creates an IP actor.
- More generally, any workflow that (1) adds another row to the
actor
table, and (2) could be performed by a logged out user (a.k.a. anon user, IP user), creates an IP actor.
- Why do I need to do this?
- Once temporary accounts are enabled, we don’t want to create any actor that has the IP address as their name.
- Much of the work that has been done so far has focused on editing (particularly via
EditPage
, whether viaaction=edit
,ApiEditPage
,ApiVisualEditorEdit
, etc). If a logged out user edits via these means, a temporary account is created for them. - However, actors can be created via other workflows (e.g. editing structured data as a logged-out user). Until these workflows are updated, MediaWiki will continue to save users whose name is their IP address.
For detailed instructions on what to do, see the sections below.
Design guidelines around this change
- Parity with IP editor rights, at first. Initially, the temporary account experience should minimally have parity with the legacy IP experience in terms of what capabilities are available to such editors. Though the architecture of temporary accounts affords opportunities to open up richer and persistent experiences to logged-out people, these opportunities should be deferred until after the initial launch so that communities have as little change as possible during this major shift.
- Temporary accounts should feel ephemeral. People should not think they have an account when they do not, and there is space for education to include highlighting the incentives of creating an account as opposed to remaining logged-out (similar to the prompts that appear for IP editors).
- Clarity that anyone can edit. Equally, it should also be clear to the person with a temporary account that it is still not required for them to create an account to continue editing. Maintaining one of the Founding principles of Wikimedia projects.
- Guidance and education incorporated in the new experience.
- People should not be jarred or confused when the account disappears.
- People should not perceive that their privacy is reduced with a temporary account compared to an IP-edit. On the contrary, consider opportunities to highlight that privacy is improved as a temporary account editor compared to an IP edit, since the IP address will no longer be shown except to privileged users.
How should I update my code?
Questions you may ask yourself
There is no single, simple answer to this question. Temporary accounts are a new way of representing anonymous editors, which could have enormous impacts on some parts of software but barely make a difference to others. Solutions might involve a lot of product research, but a straightforward technical fix. Or a technical fix might be complicated and require domain expertise and judgment.
Examples of ways code might be affected and how to consider fixing it (disclaimer: this is not exhaustive):
- A feature is unavailable to anonymous users. Should it be available to temporary users?
- A feature works differently for anonymous vs registered users. How should it work for temporary users?
- A feature assumes anonymous users are less trustworthy, and registered users are trustworthy. How should it treat temporary users?
- A feature displays different UI messages for anonymous vs registered users. What should it display for temporary users?
- A feature assumes registered users have preferences. It now needs to check for named users instead, since temporary users don’t have preferences.
- A feature assumes registered users have a watchlist. It now needs to check for named users instead, since temporary users don’t have a watchlist.
- A feature assumes registered users have rights. However, temp users will have no more rights than anonymous users (see Special:ListGroupRights), so code should be updated accordingly.
- A feature looks for the IP address in the user name (it will no longer be found). If the feature doesn’t leak the IP address (or related information, e.g. geolocation data), look in the request data instead using
$request->getIP()
. Otherwise, the feature should be discontinued or only available to checkusers, admins and users in a new “temporary account viewer” group. - Statistics are gathered separately for anonymous and registered users. How should temporary users be bucketed?
- A user is flagged as anonymous or registered (e.g. in logs or API results). How should temporary users be flagged? What would features checking these flags like to know? Note that in most APIs, temporary users are flagged separately from IP users: (T341228).
- Some feature or part of the infrastructure assumes that the
user
table will keep growing at its current rate. This assumption won’t hold after temporary accounts are enabled: theuser
table will grow more quickly. - Some feature or part of the infrastructure assumes that the ratio of registered to anonymous users accessing Wikimedia sites will stay roughly the same. This assumption won’t hold anywhere that temporary users are treated as registered users.
- A feature that relies on looking at the user’s ID to identify if the user is registered or unregistered. Temporary accounts will not have a
user_id
of 0. An example of this might be instrumentation.
We are doing an audit of features that might be affected (T349219), and will contact you if we discover you are affected. However we may not find everything.
Update a check for the type of user
In the simplest scenario, you may only need to update a check for the type of user:
Your code was checking... | You want... | Your code should now... |
---|---|---|
$user->isRegistered()
|
to treat temp users the same as registered users | no change needed |
$user->isRegistered()
|
to treat temp users the same as anon users | check $user->isNamed()
|
$user->isAnon()
|
to treat temp users the same as registered users | no change needed |
$user->isAnon()
|
to treat temp users the same as anon users | check !$user->isNamed()
|
$user->isRegistered() or $user->isAnon()
|
to treat temp users differently from registered users or anon users | add another check for $user->isTemp()
|
The UserIdentityUtils
service has the same methods and should be used when a UserIdentityUtils
is available, but not a full User
(or Authority
) object.
The UserNameUtils
service also has a method isTemp.
Similar methods are available in JavaScript via the mediawiki.util
and mediawiki.user
modules:
mw.util.isTemporaryUser
mw.user.isTemp
mw.user.isNamed
However, we have encountered more complex examples where more complicated product and technical solutions are needed. For example, when an IP address is blocked from editing, there is an option to block anonymous users only. Should this block temporary users too? Should there be a separate option? Code updates could include changes to core PHP classes, UI forms, site configuration options and the database schema. Similarly significant updates may be needed to other products.
It’s important to emphasize checking your products carefully, since they may need to be re-conceived for temporary accounts.
Anonymous, Not logged-in, Unregistered, Unnamed? A word on terminology
Description | Suggestions | Our proposal | |
---|---|---|---|
Documentation | Code | ||
Users who are recognized by their IP address | IP, Anonymous, Logged-out, Unregistered | IP users | Rename User::isAnon to User::isIP or remove it altogether
|
Users whose accounts were autocreated when performing some action | Temporary, Unnamed, Limited | Temporary users | Keep User::isTemp , or rename to User::hasTempAccount
|
Users who have been through a full registration process | Registered, Named, Regular | Permanent users | Rename User::isNamed to User::isPermanent or User::hasPermanentAccount
|
Users who have a row in the user table | Registered, Something involving "account" | Users who have an account | Rename User::isRegistered to User::hasAccount , or remove it and check User::getID instead
|
Creating a new temporary user
If your feature allows logged-out users to perform an action that creates an actor in the actor
table whose name is their IP address, you'll need instead to create a temporary account the first time a logged out user performs the action.
Attempting to create an actor with an IP address as the name now throws an error if temporary accounts are enabled.
What to do:
- File a subtask of T349129 (example subtask: T349130)
- You only need to do any of this if the permissions configuration allows anyone (group
*
) to perform the action. Keep this configuration. If a logged-out user can't perform the action, a temporary account cannot be auto-created for it. - If the action/permission your feature handles isn't
edit
, add it to the list of actions that create a temporary user, in$wgAutoCreateTempUser['actions']
. (The list containsedit
by default.) - Use the
TempUserCreator
to create a temporary user. Per T359405, do this a) once it is likely that the action will be successful (e.g. after permissions checks and other checks that might throw an error) but b) before any code that might generate log entries that would reference a failed edit attempt (e.g. AbuseFilter trips). (Note that after the temporary user is created it will be different from the global context user.) - To see an example, look at
EditPage::createTempUser
. Note thatEditPage
has the added complexity of needing to show a preview with the temporary user name, before the temporary user is created. This should be an unusual requirement, but may be re-implemented in your feature, if necessary. - In an action API handler (anything that extends
ApiBase
), use theApiCreateTempUserTrait
, which creates a login redirect URL via CentralAuth (or whichever extension handles theonTempUserCreatedRedirect
hook), with the correct values for thereturnto
,returntoquery
, andreturntoanchor
parameters. - For other (non-action API) contexts, build the redirect URL and then run the
onTempUserCreatedRedirect
hook, which modifies the URL for central login. SeeEditPage::doPostEditRedirect
for an example. - If you want to show a popup explaining what a temporary account is after the action is completed, use the
mediawiki.tempUserCreated
module.
Testing the onTempUserCreatedRedirect
hook
To test that you’re using this hook correctly, without having a full CentralAuth setup locally, you may use this snippet in your LocalSettings.php
:
$wgHooks['TempUserCreatedRedirect'][] = function (
\MediaWiki\Session\Session $session,
\MediaWiki\User\UserIdentity $user,
string $returnTo,
string $returnToQuery,
string $returnToAnchor,
&$redirectUrl
) {
if ( $returnTo === '' ) {
$returnTo = \MediaWiki\Title\Title::newMainPage()->getFullText();
}
if ( $returnToQuery === '' ) {
$returnToQuery = 'redirected-by-hook=yes';
} else {
$returnToQuery = "redirected-by-hook=yes&$returnToQuery";
}
$redirectUrl = \MediaWiki\Title\Title::newFromTextThrow( $returnTo )
->getFullURL( $returnToQuery ) . $returnToAnchor;
};
This sets the redirect URL to the given title, query and anchor (without an intermediate central login), and adds redirected-by-hook=yes
to the query so you can tell that the hook was used.
Updating AbuseFilter filters
Filters used by AbuseFilter that use IPs in their conditions may need to be updated to work with temporary accounts.
Notably, the user_name
variable is expected to no longer return an IP, breaking any condition that relies on that access.
The following migration steps are expected but is subject to change:
- Conditions that use the
ip_in_range
orip_in_ranges
will no longer work, as theuser_name
passed through will no longer contain the IP for anonymous users. Instead, a new proposed variableuser_unnamed_ip
should be used instead. Work on this is tracked via phab:T357772. - Conditions that use
user_name
to access the IP should instead use the proposeduser_unnamed_ip
variable. - Conditions that implicitly check for IPs/anonymous users (eg. via
user_age
oruser_groups
) may not work. Instead, use the newuser_type
variable which can return 'named', 'temp', 'ip', 'external', or 'unknown'. Depending on what the filter does, it may need to filter for both 'temp' and 'ip' values.
user_unnamed_ip
works for anonymous and temporary users, so filters using user_name
can be updated to use user_unnamed_ip
instead, allowing for an easier migration of filters. This should be done on each wiki before temporary accounts are deployed there.
Update documentation
Kindly add your information on the updates page as and when you complete any community-facing change relating to this project.
FAQ for developers
What's the change from a technical perspective?
A temporary account is in the user
table, and is for all intents and purposes a regular account, but with a few differences:
- A cookie will be set on the user’s browser when the account is created. This cookie will be used to attribute all subsequent edits performed by this user even if the user’s IP address changes. Essentially, there are no more edits that are attributed directly to IPs. The temporary account exists for as long as the cookie exists. The cookie is set to expire after one year from the first edit.
- There is an automatically generated username assigned to this user, and no password. As such, it is impossible to log in to this user account. The only way to be logged in as this user is to simply have an unexpired cookie that was set when the account was created.
- As for the code:
User::isRegistered()
will return true for all registered accounts, including temporary accounts.User::isAnon()
will return false for such temporary accounts.User::isTemp()
will return true exclusively for temporary accounts.User::isNamed()
will return true exclusively for registered accounts that are not temporary accounts.
- Temporary usernames will begin with an asterisk and take the general form of : ~12345 (the format is defined by the config
$wgAutoCreateTempUser['genPattern']
). - A temporary user will be represented by a row in the
user
table. A row can only be determined as representing a temporary (as opposed to registered) user via the name stored in user.user_name. A temporary user name will match the config$wgAutoCreateTempUser['matchPattern']
.
How can my code check if temp accounts is enabled?
There are two relevant methods in the TempUserConfig
interface.
isEnabled()
indicates the auto creation of temporary accounts is currently activeisKnown()
indicates that temporary accounts are a known concept on the wiki. It does not mean that auto creation of temporary accounts is currently active. It does mean that temporary accounts may exist on the wiki.
Should my tool treat temp accounts the same as regular accounts?
Depends on your feature. However, if you allow users to accrue anything on a temporary account, such as points, history or preferences, please note that the users will lose everything when the account expires. This may not be a happy outcome for those users. For everything else, treating them as regular accounts may be a safe bet, but you know your product best.
In the event that you decide to provide extra features for temporary accounts that did not exist for IP editors, please tell us, as we're tracking what extra functionality will be made available for temporary accounts compared to unregistered editors previously.
Why are temporary accounts implemented so similarly to named user accounts, if the users themselves are more similar to anonymous users?
- CentralAuth integration was a product requirement. After saving a revision, the user is logged in on all wikis. Implementing this without creating a user row would have been very challenging.
- Creating a user row allows us to share session management infrastructure with logged-in users. The long-lived cookie which keeps the temporary user logged in is identical to the “remember me” feature for regular user accounts.
- Temporary accounts are meant to represent the actions of a particular person, much like a named account. On the other hand, anonymous (IP address) actors can represent many different people, and it is expected that one person may act via several IP address actors at once.
Why does User::isRegistered
return true instead of false for a temporary account? Shouldn’t temporary users mostly be treated like anonymous users?
A temporary account behaves like a named account internally and represents a similar real-world entity (i.e. a person). This concept - and the software - would become muddled if User::isRegistered
returned false.
Many features need to treat temporary accounts the same as named users: for example, temporary users can request tokens and use these as identifiers when editing via the API, e.g. in order to build an edit history via mobile apps.
Features can be updated on a case-by-case basis to treat temporary users like anonymous users or named users (or in a different way to either).
Can our database handle the increased number of new accounts created?
We can't be sure exactly how many extra new accounts will be made, but if it's in the order of the low double-digit millions per year (as suggested by phab:T327365#8558972), then the corresponding growth of the user
and actor
tables is acceptable. The size increase of the user_properties
table would have been a concern, but temporary accounts can't save preferences, so won't add rows to this table.
What will be stored in the database instead of the IP address?
The `actor` table stores IP addresses as an actor's name in the `actor_name` column. With temporary accounts enabled, no new users will have their IP address as their name, so their temporary user name will be stored in the `actor_name` column instead.
The `ip_changes` table also stores IP addresses, but a row will not be made in `ip_changes` for an edit made by a temporary account.
Where in the database will IP addresses be stored?
IP addresses for temporary users will be stored the same way for temporary users and users with a full account. They will be stored in the CheckUser tables for a limited time, then they will be purged from the table.
Will old IP addresses be hidden? Where IP addresses are already stored in the database, will they be removed? Will it be possible to instantiate a `User` object with an IP address as its name?
After temporary accounts are enabled, any IP addresses that were visible before enabling temporary accounts will still be visible.
Those IP addresses will still exist in database tables.
It will still be possible to instantiate a `User` object with an IP address as its name.
Will this increase the amount of traffic bypassing the Varnish cache?
There should be no effect here, since recent IP editors already bypass the Varnish cache . Logged out readers will still hit it.
What is mw.config.get('wgUserName')
for a temporary user?
This will return the temporary user's name (whereas for an IP user it returns null
). This is because temporary users are implemented the same as registered users, and it may be necessary to access their name.
You can check if a user is temporary in JavaScript via the mediawiki.util
and mediawiki.user
modules:
mw.util.isTemporaryUser
mw.user.isTemp
mw.user.isNamed
What is mw.config.get('wgUserGroups')
for a temporary user?
This will return [ "*", "temp" ]
.
Can temporary users be assigned to groups, autopromoted or autoconfirmed?
No. None of these are possible for temporary users.
I'm a developer for a tool or third-party MediaWiki extension. How do I let the WMF know about my needs?
Please add tasks about your work as subtasks of phab:T326816.
PHPUnit tests for my extension break with temp accounts enabled
See phab:T365645 and phab:T365669 for example patches on how to update your tests.
I have questions not answered on this page
See:
- The general FAQ for basic information about the project, legal information, answers to functionaries' questions, etc.
- T326816 and T300263 for more technical details.
You may also reach out to us on the talk page.