# Sign-in API

> Browser sign-in with a configured provider, and sign-out.

- [List sign-in methods](#list-sign-in-methods): `GET /v1/auth/providers`
- [Start browser sign-in](#start-browser-sign-in): `GET /v1/auth/login`
- [Complete browser sign-in](#complete-browser-sign-in): `GET /v1/auth/callback`
- [Sign out](#sign-out): `POST /v1/auth/logout`

## List sign-in methods

`GET /v1/auth/providers`

The sign-in methods this service offers and its access mode, for the
sign-in page. Unauthenticated.

- **Authentication:** none on this route.
- **Who:** No authentication.

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| `200` | — | [`SignInProvidersDto`](/docs/api/schemas#signinprovidersdto) |

```sh title="Request"
curl "$VMYARD_API_URL/v1/auth/providers"
```

```json title="Response 200"
{
  "access": "open",
  "providers": [
    {
      "default": false,
      "display_name": "string",
      "kind": "oidc",
      "name": "dev"
    }
  ],
  "waitlist_url": "string"
}
```

## Start browser sign-in

`GET /v1/auth/login`

- **Authentication:** none on this route.
- **Who:** No authentication.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `provider` | query | `string` | No | Configured sign-in method such as `google` or `github`; omitted selects the default provider. |
| `return_to` | query | `string` | No | Same-origin UI path (single leading `/`, at most 2048 bytes) to open after sign-in; invalid values become `/`. |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| `303` | Redirect to `<ui>/sign-in?error=unsupported_provider\|oidc_unavailable\|oidc_failed` | — |
| `307` | Redirect to the selected OIDC provider | — |

```sh title="Request"
curl "$VMYARD_API_URL/v1/auth/login"
```

## Complete browser sign-in

`GET /v1/auth/callback`

- **Authentication:** none on this route.
- **Who:** No authentication.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `code` | query | `string` | No |  |
| `state` | query | `string` | No |  |
| `error` | query | `string` | No | OAuth error from the provider; `access_denied` maps to the `access_denied` sign-in error. |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| `303` | Signed in (or, for a linking attempt, identity linked): redirect to the stored `return_to` on the UI origin. Failure: redirect to `<ui>/sign-in?error=access_denied\|identity_in_use\|oidc_failed\|oidc_unavailable\|session_expired\|unsupported_provider` | — |
| `500` | Internal error (`internal_error`); quote the `correlation_id`. | [`ProblemDetails`](/docs/api/schemas#problemdetails) |

```sh title="Request"
curl "$VMYARD_API_URL/v1/auth/callback"
```

## Sign out

`POST /v1/auth/logout`

Ends the browser session. API keys cannot sign out; revoke the key instead.

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

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| `204` | Session revoked | — |
| `401` | Not signed in, or the API key is malformed, expired, or revoked (`unauthenticated`, `invalid_api_key`). | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `403` | Missing or invalid CSRF token, or a bearer API key (`session_required`) | [`ProblemDetails`](/docs/api/schemas#problemdetails) |

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