# Usernames

Let people sign in with a username as well as their email, and decide whether every sign-up needs one.

With usernames on, the password form on your hosted sign-in page takes a username or an email, and people choose a username when they sign up with a password or later from your app. Usernames are off until you turn them on, and the address stays the account's identity either way: a username is a second name to sign in with, not a replacement for the email.

Step by step, with screenshots: [Set up usernames](/sign-in-setup/usernames).

> **Note:**
  Turn them on under **User Management → Access → Authentication → Sign-up**, in
  the **Usernames** card, with **Allow usernames**. Usernames work with password
  sign-in, so your client needs the Email/Password method.


**Require a username at sign-up**, in the same card, makes every password sign-up choose one and stops anyone removing theirs. Accounts made before keep signing in without one. Both switches are `username: { enabled, required }` on the auth config.

## The rules

A username is 3 to 30 characters of lower-case `a` to `z`, digits, `.`, `-` and `_`, starting and ending with a letter or digit, with no two dots in a row. Typed capitals are stored lower case, so `Ada` and `ada` are the same name. Only Latin letters, so two names that look alike are the same name and nobody can register a look-alike from another alphabet.

Each is unique in your app. These are reserved and nobody may take them: `admin`, `administrator`, `root`, `support`, `help`, `system`, `api`, `null`, `undefined`, `owner`, `staff`, `security`, `billing`, `moderator` and `buildbase`.

The same rules run in the hosted page, the SDK and the server, so a name the form accepts is one the server stores. For a form of your own:

```ts
import { isValidUsername, normaliseUsername } from '@buildbase/sdk/react';

normaliseUsername('Ada.Lovelace'); // 'ada.lovelace'
normaliseUsername('admin'); // null: reserved
isValidUsername('ada..l'); // false: two dots in a row
```

## Signing in

The field on the sign-in page reads **Email or username** while usernames are on. Magic links and email codes still need an address, since they are sent to it.

A username that does not exist, and a wrong password, get the same answer: "Invalid username or password." The page cannot be used to find out which usernames are taken. If you call the API yourself, send `username` in place of `email` to `POST /api/v1/auth/login`.

## Choosing one

- **At sign-up.** The register page asks for a username beside the password, required or optional as you set it. Other ways of signing up, such as a social provider, a code or a phone, do not ask; those people add one later.
- **From your app.** The SDK's Profile screen shows a **Username** field while usernames are on or the person has one. It offers **Remove** unless you require one. Hide it with `ui.settings.profile.username: false`.
- **From your own screen:**

```ts
await api.setUsername('ada.lovelace'); // { username }
await api.removeUsername();
```

`api` is a `WorkspaceApi`. `useSaaSAuth().user.username` holds the current one, and `AuthApi.getUsernamePolicy(orgId)` reads `{ enabled, required }` from your public auth config.

| Route                                    | Answers                   |
| ---------------------------------------- | ------------------------- |
| `PUT /api/v1/public/profile/username`    | `{ username }`, as stored |
| `DELETE /api/v1/public/profile/username` | `{ success }`             |

| Refusal                   | When                                    |
| ------------------------- | --------------------------------------- |
| `400` `invalid_username`  | The name breaks a rule above            |
| `409` `username_taken`    | Another account here has it             |
| `400` `usernames_off`     | Your app has usernames off              |
| `409` `username_required` | Removing it while your app requires one |

Turning usernames off never refuses a sign-up that sends one: an older page or SDK that still sends a username is let through, and the name is ignored.

## Elsewhere

- **Webhooks.** The `actor` object a delivery carries includes `username` when the person has one.
- **Importing.** An [import](/authentication/importing-users) line can carry `username`. One that breaks the rules, or is taken here, is left off with a warning and the user is imported without it.
- **Deleting.** A deleted account's username is freed with the rest of its data.

## Next steps

- [Sign In & Sign Out](/authentication/sign-in-sign-out) - `useSaaSAuth()` and the user it returns.
- [Who can sign up](/authentication/signup-access) - the other card on the Sign-up tab.
- [Importing Users](/authentication/importing-users) - bring usernames over from another system.
