# Auth · Usernames and phones

> Looking up an identity by username or phone number, checking availability, and username recovery.

Three directories map an identifier to an identity: usernames, email addresses and phone numbers. This page covers
usernames and phones; addresses are on [the email page](/docs/auth-email).

## 404 is the good answer

Each item route answers `404` when nothing claims the identifier. That is the successful response to "is
this available?", and the one a registration form is waiting for as somebody types. Use `HEAD` for the
check — it performs the same lookup without moving any identity data over the wire.

## Listing is admin-only

The collection routes list everything claimed on the deployment, so they sit behind the admin guard. The item routes
are open, because resolving one identifier you already know is what every sign-in screen does.

## List usernames

`GET /api/auth/username`

Guard: admin

Every username claimed on the deployment, paged by cursor.

### Parameters

- `prefix` _string_ — Narrow to usernames starting with this. Query parameter.
- `cursor` _string_ — Continue from a previous page. Query parameter.
- `limit` _number_ — Page size. Defaults to the deployment list limit.

### Returns

The page of usernames, and a cursor when there is more.

### Request (cURL)

```
curl "https://example.com/api/auth/username?limit=2" \
  -H "authorization: Bearer $TOKEN"
```

### Response

```json
{
  "usernames": ["ada", "grace"],
  "cursor": "01J2788XY98FDTA410C8S716CD"
}
```

## Look up the identity behind a username

`GET /api/auth/username/:username`

Guard: open

Resolves a username to the identity that claimed it. A username nobody has claimed answers
`404` — which is the _good_ answer to "is this available?", and the one a registration
form is waiting for as somebody types.

### Parameters

- `username` _string_ **Required** — Path parameter.

### Returns

`{ identity }`, or `404` when the username is free.

### Request (cURL)

```
curl https://example.com/api/auth/username/ada
```

### Response

```json
{
  "identity": {
    "id": "01J2788XY98FDTA410C8S716CD",
    "kind": "member",
    "displayName": "Ada Lovelace"
  }
}
```

## Check whether a username is taken

`HEAD /api/auth/username/:username`

Guard: open

The same lookup without the body — the right call for an availability check, since it moves no identity data over the wire.

### Parameters

- `username` _string_ **Required** — Path parameter.

### Returns

`200` when taken, `404` when free. No body either way.

### Request (cURL)

```
curl -I https://example.com/api/auth/username/ada
```

### Response

```json
{}
```

## Begin username recovery

`POST /api/auth/username/:username/recovery/challenge`

Guard: open

Sends a recovery challenge to whatever contact the identity behind the username has. Answers
`200` whether or not the username exists, so it cannot be used to enumerate accounts.

### Parameters

- `username` _string_ **Required** — Path parameter.
- `kind` _enum_ — The authentication payload the challenge is for.
  - One of: `username`
- `method` _enum_ — How the recovery should be delivered.
  - One of: `verification`, `code`

### Returns

`200`, always.

### Request (cURL)

```
curl -X POST https://example.com/api/auth/username/ada/recovery/challenge \
  -H "content-type: application/json" \
  -d '{ "kind": "username", "method": "verification", "username": "ada" }'
```

### Response

```json
{
  "ok": true
}
```

## Complete username recovery

`POST /api/auth/username/:username/recovery`

Guard: open

Redeem the verification that `POST …/recovery/challenge` sent, and get a session back — this is
how somebody who has lost their passphrase gets in far enough to set a new one.

### Parameters

- `username` _string_ **Required** — Path parameter.
- `verification` _string_ **Required** — The token from the recovery challenge.

### Returns

A session, with both cookies set.

### Request (cURL)

```
curl -X POST https://example.com/api/auth/username/ada/recovery \
  -H "content-type: application/json" \
  -d '{ "verification": "01J2788XY98FDTA410C8S716CD" }'
```

### Response

```json
{
  "identity": { "id": "01J2788XY98FDTA410C8S716CD", "kind": "member" },
  "identityToken": "eyJhbGciOi…",
  "refreshToken": "eyJhbGciOi…"
}
```

## List phone numbers

`GET /api/auth/phone`

Guard: admin

Every phone number registered on the deployment, paged by cursor.

### Parameters

- `prefix` _string_ — Narrow to numbers starting with this. Query parameter.
- `cursor` _string_ — Continue from a previous page. Query parameter.
- `limit` _number_ — Page size. Defaults to the deployment list limit.

### Returns

`{ phones }`.

### Request (cURL)

```
curl https://example.com/api/auth/phone \
  -H "authorization: Bearer $TOKEN"
```

### Response

```json
{
  "phones": ["+15550100", "+15550101"]
}
```

## Look up the identity behind a phone number

`GET /api/auth/phone/:phone`

Guard: open

Resolves a phone number to the identity that registered it. `404` when nothing claims it.

### Parameters

- `phone` _string_ **Required** — Path parameter, URL-encoded.

### Returns

`{ identity }`, or `404`.

### Request (cURL)

```
curl https://example.com/api/auth/phone/%2B15550100
```

### Response

```json
{
  "identity": {
    "id": "01J2788XY98FDTA410C8S716CD",
    "kind": "member",
    "displayName": "Ada Lovelace"
  }
}
```

## Check whether a phone number is registered

`HEAD /api/auth/phone/:phone`

Guard: open

The same lookup with no body.

### Parameters

- `phone` _string_ **Required** — Path parameter, URL-encoded.

### Returns

`200` when registered, `404` when not.

### Request (cURL)

```
curl -I https://example.com/api/auth/phone/%2B15550100
```

### Response

```json
{}
```
