Короткий ответ
В Authorization Code Flow backend перенаправляет пользователя на провайдера, получает обратно одноразовый код авторизации на заранее зарегистрированный redirect_uri и обменивает его на токены на сервере; параметр state — случайное значение, которое backend генерирует перед редиректом и проверяет при возврате, что защищает от CSRF-атаки на сам процесс логина.
Как это работает подробнее
Backend сохраняет сгенерированный state (например, в сессии пользователя), отправляет пользователя на провайдера с этим state, провайдер возвращает его без изменений вместе с кодом авторизации на redirect_uri, и backend сверяет полученный state с сохранённым, прежде чем продолжить обмен кода на токены.
Пример кода
example.txt
1. Backend генерирует state=random_abc и сохраняет его в сессии.
2. Backend перенаправляет пользователя на URL:
GET https://accounts.google.com/o/oauth2/v2/auth?client_id=web-client-123&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&state=random_abc
3. Провайдер возвращает пользователя:
GET /callback?code=auth_code_xyz&state=random_abc
4. Backend сравнивает state из запроса со значением в сессии.
5. Backend обменивает code на токены по серверному каналу.Что использовать на практике
- Практика. Обмен authorization code на access/id-токен должен происходить на backend напрямую с провайдером (server-to-server) с использованием client_secret, а не в браузере; для публичных клиентов (SPA, мобильные приложения) без возможности хранить secret используют PKCE вместо client_secret.
Подводные камни
- Риск. Пропускают проверку state, что открывает возможность login CSRF; доверяют данным из id_token без проверки его подписи, издателя (iss), аудитории (aud) и срока действия; хранят client_secret на фронтенде вместо backend.