# Sign-in methods API

> Link another sign-in method to the signed-in user, or remove one.

- [Link a sign-in method](#link-a-sign-in-method): `POST /v1/auth/link/{provider}`
- [Remove a sign-in method](#remove-a-sign-in-method): `DELETE /v1/auth/login-methods/{login_method_id}`

## Link a sign-in method

`POST /v1/auth/link/{provider}`

Starts linking `provider` to the signed-in user. For a redirect provider
the response carries the authorization URL and a browser-bound state
cookie; for `email` a code and link are sent to the address and
`POST /v1/auth/email/verify` (with this session) completes the link.

- **API key:** not accepted (`403 session_required`).
- **Browser session:** the `vmyard_session` cookie and the `x-csrf-token` header.
- **Who:** The signed-in user.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `provider` | path | `string` | Yes | Configured provider such as `github`, `google`, or `email` |

**Request body** (`application/json`, [`LinkRequest`](/docs/api/schemas#linkrequest))

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | `string \| null` | No | Required for `email`, refused for other providers. |
| `return_to` | `string \| null` | No | Same-origin UI path to open when the provider flow completes; invalid values become `/`. |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| `200` | Navigate to `authorization_url` | [`LinkStarted`](/docs/api/schemas#linkstarted) |
| `202` | Email linking: a code was sent if the address can receive email | [`EmailStarted`](/docs/api/schemas#emailstarted) |
| `401` | Not signed in, or the API key is malformed, expired, or revoked (`unauthenticated`, `invalid_api_key`). | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `403` | `csrf_invalid`, `session_required` (API key), or `recent_auth_required` | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `404` | `unsupported_provider` | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `422` | Invalid request (`invalid_request`); `field_errors` names the fields. | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `429` | Too many requests; wait for `Retry-After`. | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `503` | Not available on this server. | [`ProblemDetails`](/docs/api/schemas#problemdetails) |

```sh title="Request"
curl -X POST "$VMYARD_API_URL/v1/auth/link/$PROVIDER" \
  -b "vmyard_session=$VMYARD_SESSION" \
  -H "x-csrf-token: $VMYARD_CSRF" \
  -H "Content-Type: application/json" \
  -d '{
  "return_to": "/"
}'
```

```json title="Response 200"
{
  "authorization_url": "string"
}
```

## Remove a sign-in method

`DELETE /v1/auth/login-methods/{login_method_id}`

Removes one of the signed-in user's sign-in methods. The last method
cannot be removed. Existing sessions stay valid.

- **API key:** not accepted (`403 session_required`).
- **Browser session:** the `vmyard_session` cookie and the `x-csrf-token` header.
- **Who:** The signed-in user.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `login_method_id` | path | `string (uuid)` | Yes |  |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| `204` | Removed | — |
| `401` | Not signed in, or the API key is malformed, expired, or revoked (`unauthenticated`, `invalid_api_key`). | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `403` | `csrf_invalid`, `session_required` (API key), or `recent_auth_required` | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `404` | Not one of this user's methods | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `409` | `last_login_method` | [`ProblemDetails`](/docs/api/schemas#problemdetails) |

```sh title="Request"
curl -X DELETE "$VMYARD_API_URL/v1/auth/login-methods/$LOGIN_METHOD_ID" \
  -b "vmyard_session=$VMYARD_SESSION" \
  -H "x-csrf-token: $VMYARD_CSRF"
```
