# VK ID API: Продлевать сессию без повторного входа

Сценарий из mcp-everything. Актуально на 2026-10-24.

Пользователь остаётся залогиненным неделями, хотя access_token живёт всего час.

1. Когда access_token истёк (или вот-вот истечёт по expires_in), вызови POST /oauth2/auth с grant_type = refresh_token, refresh_token, client_id, device_id (тот, что пришёл при входе) и state.
2. В ответе новая пара access_token и refresh_token, id_token не возвращается. Старая пара сразу перестаёт работать — сохраняй новую атомарно, иначе при параллельных запросах пользователя выкинет из сессии.
3. Делай обновление в одном месте (например, с блокировкой по пользователю), а не из каждого запроса отдельно.
4. Ошибка invalid_token значит, что refresh_token отозван или устарел: отправь пользователя на вход заново.

```bash
curl -s -X POST https://id.vk.ru/oauth2/auth \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d grant_type=refresh_token \
  -d refresh_token=<refresh_token> \
  -d client_id=<client_id> \
  -d device_id=<device_id> \
  -d state=$(openssl rand -hex 24)
```

## Базовые URL

- Боевой: `https://id.vk.ru`

## Авторизация

Тип: OAuth 2.0

Пользователь проходит `GET /authorize` и возвращается на `redirect_uri` с `code` и `device_id`; код обменивается на `access_token`, `refresh_token` и `id_token` методом `POST /oauth2/auth`. PKCE обязателен: `code_verifier` — 43–128 символов, `code_challenge` — base64url от SHA-256 строки `code_verifier`. Access token действует 1 час.

## Методы сценария

### POST /oauth2/auth — Обмен кода на токены

`grant_type=authorization_code`. В ответе: `access_token`, `refresh_token`, `id_token`, `token_type`, `expires_in`, `user_id`, `state`, `scope`.

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `grant_type` | body | string | да | authorization_code |
| `code` | body | string | да | Код из редиректа |
| `code_verifier` | body | string | да | Исходная строка PKCE |
| `redirect_uri` | body | string | да | Тот же адрес возврата |
| `client_id` | body | string | да | ID приложения |
| `device_id` | body | string | да | device_id из редиректа |
| `state` | body | string | да | Строка state |
| `service_token` | body | string | нет | Для конфиденциальных приложений |
| `ip` | body | string | нет | IP пользователя |

### POST /oauth2/auth — Обновление токенов

`grant_type=refresh_token`. Возвращает новую пару `access_token` и `refresh_token` (без `id_token`); старая пара инвалидируется.

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `grant_type` | body | string | да | refresh_token |
| `refresh_token` | body | string | да | Refresh-токен |
| `client_id` | body | string | да | ID приложения |
| `device_id` | body | string | да | ID устройства |
| `state` | body | string | да | Строка state |
| `scope` | body | string | нет | Права |
| `service_token` | body | string | нет | Для конфиденциальных приложений |
| `ip` | body | string | нет | IP пользователя |

## Нюансы

- Из браузера токен передаётся только в теле запроса с `Content-Type: application/x-www-form-urlencoded`: заголовок `Authorization` и JSON вызывают ошибку preflight CORS.
- Неверный `grant_type` или `response_type` даёт ответ 404.
- После обновления токенов старая пара `access_token`/`refresh_token` перестаёт работать.
- `public_info` работает с `id_token` и отдаёт маскированные данные, `user_info` — с `access_token` и полные данные.

## Другие сценарии

- [Сделать вход через VK ID на сайте](https://mcp-everything.ru/integrations/vk-id/scenarios/sdelat-vhod-cherez-vk-id-na-sayte.md)
- [Показать «Продолжить как …» и выйти из аккаунта](https://mcp-everything.ru/integrations/vk-id/scenarios/pokazat-prodolzhit-kak-i-vyyti.md)

---

Если этого недостаточно — официальная документация: https://id.vk.ru/about/business/go/docs/ru/vkid/latest/vk-id/connection/api-description
Вся интеграция одним документом: https://mcp-everything.ru/integrations/vk-id.md
