Почему кнопка «Войти через VK» заняла три дня. Кейс

от автора

На первый взгляд, Social Login — одна из самых простых функций современного веб-приложения.

Добавить кнопку «Войти через VK». Добавить кнопку «Войти через Яндекс». OAuth 2.0 и OpenID Connect давно стандартизированы. Документации и библиотек полно. Да и AI сегодня умеет писать интеграции быстрее человека. Поэтому, когда я решил добавить VK ID и Яндекс ID в Авторизу, честно, рассчитывал уложиться в один рабочий день:

  • Свою систему знаю.

  • OIDC знаю.

  • Подобные интеграции раньше проектировал.

  • Под рукой ChatGPT, Claude и AI-агенты.

Что вообще может пойти не так?

Спойлер: получилось почти три дня. И самой сложной частью оказался не OAuth.

День первый. Самоуверенность

План выглядел очень оптимистично.

  1. Немного почитать документацию.

  2. Создать приложения в кабинетах VK и Яндекса.

  3. Продумать архитектуру.

  4. Попросить AI написать типовой код.

  5. Докрутить интерфейс.

Ну максимум восемь часов.

На практике первые два часа ушли… только на чтение документации с околонулевым результатом. И даже не потому, что OAuth оказался сложным. А потому что было совершенно непонятно, куда вообще смотреть.

Когда документация — это зло

В таких случаях, когда я владею базой, я читаю документацию “по диагонали”, выискивая ценную для меня информацию, которая решит мою текущую задачу. Но в этом случае не сработало.

Документация VK оказалась сильно разветвленной. Каждая страница отправляет читать еще две. Потом еще и еще. В какой-то момент я поймал себя на том, что у меня открыто восемь вкладок, между которыми я постоянно прыгаю, пытаясь удержать взаимосвязи в голове.

Зачем мне столько вкладок для подключения стандартного протокола?

Зачем мне столько вкладок для подключения стандартного протокола?

И это при том, что я уже понимал сам протокол. Я не изучал OAuth, я пытался понять особенности реализации конкретного провайдера.

Ок, подловили, я переоценил себя, 20 минут не хватило. Поехали дальше.

«Быстрый старт», который оказался совсем не быстрым

Первым делом я открыл раздел «Быстрый старт». Логично же.

Но довольно быстро понял, что «быстрый старт» — это, по сути, инструкция по внедрению фирменного SDK.

Я решил, что альтернативы нет. Начал проектировать архитектуру вокруг SDK. Начал писать интеграцию. Продумывать взаимодействие компонентов. А потом… совершенно случайно наткнулся на документацию по классическому OAuth-подключению.

Оказалось, что оно существует. И весь код, который я уже успел написать под SDK, можно было удалить. Боль!

Это был еще один неприятный урок. Обидно за написанный код, который приходится выбрасывать. Зато есть интересное наблюдение — подключение по стандартному протоколу заняло у меня не больше времени, чем подключение через SDK. Так себе «Быстрый старт»…

Почему я принципиально отказался от SDK

Даже если оставить за скобками потерянное время, использовать SDK я все равно не хотел. Во-первых, SDK собирает дополнительную аналитику. Во-вторых, часть происходящего становится неуправляемой.

А Авториза изначально строится вокруг идеи privacy-first. Пользовательские данные не прости… (…те меня, господа, за сквернословие). Нечего по рукам их пускать. Поэтому классический OAuth оказался гораздо ближе к философии продукта.

Да, пришлось потратить дополнительное время. Хотя не так уж много. Зато вся аутентификация полностью контролируется нашим сервером.

Самая дорогая ошибка оказалась… в тексте ошибки

Следующий сюрприз ждал при регистрации приложения.

Я указал Redirect URI на локальную машину. Получил ошибку. Из текста ошибки следовало, что требуется HTTPS, что для localhost становится проблемой.

Ну хорошо. Поднял небольшой внешний тестовый сервер с сертификатом Let’s Encrypt. Настроил проксирование. Добавил редиректы. Запрос уходил на публичный сервер, оттуда пересылался в VK, затем ответ возвращался обратно и перенаправлялся в локальное окружение. На это ушло еще несколько часов. 

А потом выяснилось интересное.

localhost использовать можно. Нельзя использовать… порт.

То есть проблема была вовсе не в локальной разработке. Я до этого пытался прописать номер порта в redirect_uri. Ладно. Пришлось удалить уже работающее решение опять боль!, вернуть всё обратно и перестроить локальное окружение под новые ограничения.

Наверное, это не столько проблема реализации, сколько качества текста ошибки. Иногда одна неточная формулировка стоит разработчику нескольких часов. Каюсь — мы в Авторизе тоже на днях нашли одно такое место с некорректным текстом ошибки, исправим в ближайшее время (UPD: пока писал статью уже исправили). 

Еще одна мелочь, которая тоже съела время

Для любого внешнего сервиса OAuth я всегда регистрирую два приложения.

Одно для разработки, второе — для продакшена. Это позволяет не смешивать реальные пользовательские данные с тестовыми. Казалось бы, простая практика.

Но неожиданно оказалось, что полностью скопировать настройки приложения в VK не так просто. Часть параметров находится на одном экране. Часть — на другом.

В результате в продакшене я забыл включить необходимые claims. На тестовом окружении всё работало. На боевом — нет. Полчаса мы, на пару с QA, искали причину.

В Яндекс ID эта часть понравилась значительно больше. Большинство настроек находится в одном месте, поэтому переносить конфигурацию оказалось намного проще.

Ловушка “состояния потока”

Получить данные пользователя – это был не конец. Как только закончил с получением, появились вопросы:

  • Если пользователь уже зарегистрирован через email, а теперь входит через VK – что делать?

  • Если позже он войдет через Яндекс?

  • Если у VK изменится email?

  • Если новый email уже принадлежит другому пользователю?

  • Нужно ли хранить связь между внутренним пользователем и внешним провайдером?

  • Создавать ли отдельные таблицы?

  • Добавлять ли идентификаторы провайдеров в JWT?

  • Разрешать ли пользователю самостоятельно отвязывать аккаунты?

  • Что произойдет после подключения третьего провайдера?

  • А пятого?

В какой-то момент голова буквально начала взрываться от количества сценариев.

И тогда я понял очень неприятную вещь — я перестал решать исходную задачу. Я начал проектировать универсальную систему управления внешними идентичностями. Хотя бизнесу требовалось всего лишь добавить вход через VK и Яндекс. 

Почему? Потому, что я уже вышел за дедлайн исходного плана, задача усложнилась, архитектура несколько раз менялась, контекст размылся, и меня засосало в “состояние потока”. Я забыл об исходном требовании, и увлекся решением задачи, а не достижением цели. Увы, бывает.

Иногда лучшая архитектура — не строить архитектуру

В этот момент пришлось сознательно остановиться и задать себе простой вопрос . “Что именно требуется прямо сейчас?” Ответ оказался неожиданно коротким.

Мне нужна аутентификация. Не управление идентичностями и не сложные связи. Не десятки сценариев объединения аккаунтов и не универсальная модель данных. Мне нужно только подтвердить, что пользователь действительно является владельцем своей учетной записи у внешнего провайдера.

На этом основании решение резко упростилось.

Я иду к провайдеру аутентификации. Получаю подтвержденный email. Ищу пользователя по email. Если пользователь найден — выполняю вход. Если нет — создаю нового.

Всё.

  • Без хранения дополнительных связей. 

  • Без новых таблиц. 

  • Без новых экранов управления. 

  • Без попыток заранее решить проблемы, которых пока не существует. 

  • Я сознательно отказался от поддержки входа по номеру телефона. 

  • Сознательно отказался от хранения связей с внешними аккаунтами. 

  • Отказался от большого количества сценариев объединения. 

Это не “неправильные вещи”. Просто они не создают ценности пользователю именно сейчас. Когда дорастем до таких требований — тогда и вкрутим соответствующую архитектуру. Сегодня это был бы обычный оверинжиниринг.

В общем, закончил задачу за несколько часов, сэкономил себе неделю.

Что получилось

Сейчас в Авторизе реализована единая точка обработки внешней аутентификации. Все запросы проходят через общий механизм. Особенности каждого провайдера инкапсулированы в отдельных обработчиках. Где-то отличается формат отправляемых параметров. Где-то — модель данных пользователя. Где-то — получение пользовательской информации после авторизации. Но вся остальная логика остается общей.

Следующий провайдер уже не потребует трех дней. При условии нормальной документации и более-менее стандартной реализации OAuth его подключение должно занять примерно один рабочий день.

Что я вынес из этой истории

Когда начинал работу, мне казалось, что самая сложная часть — реализовать OAuth. Ладно, ошибался. OAuth — это вообще не проблема. Проблема — всё, что находится вокруг:

  • Документация.

  • Особенности конкретного провайдера.

  • Неочевидные ограничения.

  • Архитектурные решения.

  • И борьба с самим собой %).

Еще раз убедился в практической пользе сервисов вроде Auth0, Clerk, FusionAuth или Авторизы. Они продают, собственно, не OAuth. Потому что OAuth реализовать относительно несложно. Они продают сотни часов инженерного опыта, которые уже однажды были потрачены на подобные мелочи. Чтобы следующему разработчику не пришлось снова открывать восемь вкладок документации и три часа искать проблему, которая оказалась всего лишь запретом на использование порта в Redirect URI.

После этой работы Авториза научилась выступать не только как собственный провайдер аутентификации, но и как единая точка входа через внешние сервисы. Сейчас уже поддерживаются VK ID и Яндекс ID, а список провайдеров будет постепенно расширяться. Для наших клиентов — разработчиков, это означает простую вещь: интеграцию с внешними провайдерами достаточно выполнить один раз — через Авторизу. Когда появится поддержка нового Social Login, менять код вашего приложения уже не потребуется. Он просто станет доступен всем пользователям клиентов.

Не повторяйте моих ошибок)
Всем добра!

ссылка на оригинал статьи https://habr.com/ru/articles/1065576/