# OAuth Schema - VoIdea **Дата:** 2026-05-10 **Статус:** Backlog (для фиксации ADR) --- ## Обзор Схема авторизации: один пользователь = один провайдер. Нельзя привязать Google если уже есть Яндекс. --- ## Правила ### Основное правило > Один пользователь = один провайдер (email или OAuth) Это означает: - Если зарегистрировался через Яндекс → только Яндекс - Если зарегистрировался через Google → только Google - Если зарегистрировался через email → только email + пароль ### Нельзя - Привязать Google к аккаунту зарегистрированному через Яндекс - Добавить второй OAuth провайдер - Изменить email после регистрации через OAuth --- ## Структура данных ### Users table ```sql CREATE TABLE users ( id UUID PRIMARY KEY, email VARCHAR(255) UNIQUE, password_hash VARCHAR(255), -- NULL если OAuth-only -- OAuth данные (один провайдер) oauth_provider VARCHAR(20), -- yandex|google|apple|null oauth_id VARCHAR(255), -- ID в системе провайдера -- Метаданные email_verified BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), -- Constraints CONSTRAINT users_oauth_xor_email CHECK ( (oauth_provider IS NOT NULL AND email IS NOT NULL) OR (oauth_provider IS NULL AND email IS NOT NULL AND password_hash IS NOT NULL) ) ); CREATE UNIQUE INDEX uq_users_oauth ON users(oauth_provider, oauth_id) WHERE oauth_provider IS NOT NULL; ``` ### Почему один провайдер 1. **Безопасность** — меньше точек входа 2. **Простота** — не нужно merge аккаунтов 3. **Ясность** — пользователь знает что использует 4. **Privacy** — данные не смешиваются между провайдерами --- ## OAuth Flow ### Яндекс ``` 1. Пользователь нажимает "Войти через Яндекс" 2. Редирект на Яндекс OAuth 3. Callback с code 4. Получение access_token 5. Получение данных пользователя 6. Поиск/создание user по oauth_provider + oauth_id 7. Создание JWT session ``` ### Google Аналогично Яндексу, с заменой endpoint-ов. --- ## Регистрация через email ```sql -- При регистрации через email INSERT INTO users (email, password_hash, oauth_provider, oauth_id) VALUES ('user@example.com', 'hash123', NULL, NULL); ``` ### Вход через email ```sql -- Проверка пароля SELECT * FROM users WHERE email = 'user@example.com' AND password_hash = verify('hash123'); ``` --- ## Защита от привязки чужого аккаунта ### Проблема Злоумышленник может попытаться привязать Google к чужому email. ### Решение 1. **Email verification** — требуется подтверждение 2. **Password check** — для существующих пользователей 3. **Separate tables** — OAuth и email разделены логически --- ## Будущее (Apple OAuth) ### Apple будет реализован позже Для Apple потребуется: - App Store Developer Account - Private Key для подписи - Тот же принцип: один пользователь = один провайдер --- ## TODO - [ ] Реализовать OAuth service - [ ] Интегрировать Яндекс OAuth - [ ] Интегрировать Google OAuth - [ ] Зарезервировать место для Apple (не реализовывать) - [ ] Тесты - [ ] Документация --- *Создано: 2026-05-10* *См. также: docs/adr/003-oauth-schema.md*