Ниже — сжато и по шагам: причины типичных проблем и рабочая реализация. Большинство ошибок — из‑за неправильного flow (implicit vs code), mismatch redirect_uri, или неправильно обработанного ответа (фрагмент #access_token недоступен на сервере).
1) Выясните, какой OAuth‑flow вы используете
- response_type=code — рекомендуемый серверный flow: VK возвращает код в query (?code=...), вы на сервере обмениваете код на access_token.
- response_type=token — implicit (клиентский) flow: VK возвращает токен в фрагменте URL после # (например #access_token=...). Серверная страница при редиректе не видит fragment (оно не отправляется на сервер). Частая ошибка — ожидать code, а использовать response_type=token, либо наоборот.
Если вы сейчас получаете возврат на /login.php без токена — скорее всего вы используете implicit и не парсите fragment на клиенте, или используете code, но неправильно обмениваете код.
2) Проверьте настройки приложения в ВК
- Redirect URI должен строго совпадать с тем, который вы передаёте (полный URL, протокол, слеши).
- В настройках приложения укажите Platform = Website и укажите адрес сайта (и домен).
- Если приложение типа Standalone/Native — поведение другое. Для сайта нужно Website.
3) Общий чеклист для отладки
- Посмотрите URL, на который ВК делает редирект: есть ли ?code=... или ?error=... или после #access_token...
- Логируйте/выводите $_GET и $_SERVER['QUERY_STRING'] в login.php, чтобы увидеть что реально приходит.
- Убедитесь, что redirect_uri URL кодирован и совпадает с тем, что в настройках.
- Для серверных запросов к oauth.vk.com/access_token — используйте client_id и client_secret, корректную redirect_uri и полученный code.
- Проверьте, что session_start() вызывается, если вы храните state/сессию.
- Включите отображение ошибок и логов (или запишите ответ от VK в файл).
4) Пример правильной реализации (рекомендуется response_type=code — серверный flow)
a) Ссылка для начала авторизации:
https://oauth.vk.com/authorize?client_id=ВАШ_APP_ID&display=page&redirect_uri=https://example.com/login.php&scope=email&response_type=code&v=5.131&state=RANDOM
- state — случайная строка для защиты от CSRF (сохраните в сессии перед редиректом и проверяйте при возврате).
b) login.php — обработчик (упрощённо, PHP):
- На странице, если нет $_GET['code'], выводим ссылку на authorize.
- Если есть $_GET['error'] — покажите/запишите её.
- Если есть $_GET['code']:
1. Сравните state с сохранённым.
2. Выполните запрос:
https://oauth.vk.com/access_token?client_id=APP_ID&client_secret=APP_SECRET&redirect_uri=https://example.com/login.php&code=ПОЛУЧЕННЫЙ_CODE
3. В ответе получите JSON с access_token, expires_in, user_id и, если scope=email — поле email.
4. При success можно запросить users.get для дополнительных полей:
https://api.vk.com/method/users.get?user_ids=USER_ID&fields=first_name,last_name,photo_100&access_token=ACCESS_TOKEN&v=5.131
5. Создайте сессию/пользователя в БД и редиректите на защищённую страницу.
Пример кода обмена (PHP, cURL, упрощённо):
- (псевдокод)
<?php
session_start();
if (isset($_GET['error'])) {
// логируем
exit('OAuth error: '.htmlspecialchars($_GET['error']));
}
if (!isset($_GET['code'])) {
// вывести ссылку на authorize
echo '<a href="https://oauth.vk.com/authorize?client_id=APP_ID&redirect_uri=' . urlencode('https://example.com/login.php') . '&response_type=code&scope=email&v=5.131&state=XYZ">Войти через ВК</a>';
exit;
}
// проверяем state
$code = $_GET['code'];
$tokenUrl = 'https://oauth.vk.com/access_token?client_id=APP_ID&client_secret=APP_SECRET&redirect_uri=' . urlencode('https://example.com/login.php') . '&code=' . $code;
$ch = curl_init($tokenUrl);
// выполнить и получить ответ
$response = curl_exec($ch);
// обработать json_decode, проверить на наличие access_token
?>
5) Если вы все же используете implicit (response_type=token)
- Токен попадает в fragment (location.hash), поэтому нужно получить его через JS на странице редиректа и отправить на сервер (например POST), либо переписать URL так, чтобы серверный код получил токен (не идеально с точки зрения безопасности). Лучше — перейти на response_type=code.
6) Частые ошибки и их решения
- redirect_uri не совпадает: VK просто не отдаёт токен/код и может вернуть на исходную. Решение: привести в точное соответствие.
- Использование response_type=token, а вы ожидаете $_GET['code']: исправьте flow.
- Не URL-энкодили redirect_uri при запросах к /access_token.
- Забыл client_secret при exchange.
- Потеря state/session из‑за отсутствия session_start() или редиректа с другим доменом.
- Ожидание email через users.get — email возвращается только в ответе /access_token (если вы запросили scope=email).
7) Рекомендации по отладке
- Включите xdebug/логи и смотрите raw ответ от https://oauth.vk.com/access_token.
- Откройте DevTools (Network) и посмотрите редиректы: какая строка приходит с VK, есть ли code/fragment.
- Попробуйте воспроизвести шаг вручную в браузере — перейти по authorize ссылке и посмотреть, что приходит в адресной строке.
Если хотите, пришлите:
- точную authorize ссылку, которую вы используете (замените client_secret на ****),
- URL редиректа (как выглядит адрес при возврате — скопируйте из адресной строки),
- кусок кода login.php (как вы обрабатываете $_GET),
— и я укажу точную причину и поправлю код.