Автентикация
Licensing Server поддържа два механизма за автентикация: OAuth 2.0 (Google, Azure/Microsoft, GitHub) и Email/Password. И двата издават JWT токени за последващ достъп до API-то.
Общ поток на автентикация
OAuth Flow (Google, Azure, GitHub)
1. Login Page (GET /auth/login-page)
Desktop клиентът отваря browser с URL:
{BASE_URL}/auth/login-page?redirect_uri=http://localhost:PORT/callback&state=random&device_id=DEVICE_HASH&lang=bg
Handler-ът:
- Запазва
redirect_uri,stateиdevice_idв session cookie - Рендерира
login.htmlс Turnstile site key и i18n strings
2. OAuth Redirect (GET /auth/login/:provider)
Когато потребителят кликне OAuth бутон:
- Зарежда
redirect_uri,stateиdevice_idот session-а - Генерира 32-byte криптографски nonce (
crypto/rand) - Запазва nonce-а в session-а
- Пренасочва към OAuth provider-а с
state=nonce
Поддържани providers:
| Provider | UserInfo URL | Scopes |
|---|---|---|
googleapis.com/oauth2/v3/userinfo | openid, email, profile | |
| Azure | graph.microsoft.com/v1.0/me | openid, email, profile, User.Read |
| GitHub | api.github.com/user + /user/emails | user:email |
3. OAuth Callback (GET /auth/callback/:provider)
Nonce валидация: state параметърът от callback-а се сравнява с nonce-а, запазен в session-а. При несъответствие заявката се отхвърля с 400.
User upsert: GetOrCreateUser търси по (provider, provider_id). Ако потребителят съществува, обновява email, name и avatar. Ако не -- създава нов с plan = "free" (или DEV_DEFAULT_PLAN в dev) и trial_started_at = NOW().
4. Token Refresh (POST /auth/refresh)
POST /auth/refresh
{"token": "existing_jwt"}
- Декодира и валидира JWT-то (не е нужно да е изтекло)
- Зарежда потребителя от DB по
user_idот claims - Издава нов JWT с актуален план и email
Rate limit: 30 req/min per IP.
Email/Password Flow
Регистрация (POST /auth/register)
POST /auth/register
{
"email": "user@example.com",
"password": "min8chars",
"name": "John",
"cf-turnstile-response": "turnstile_token",
"lang": "bg"
}
Поток:
- Валидация на Turnstile token (bot protection)
- Проверка: парола >= 8 символа, валиден email
- Проверка за дублиран email (всички providers, не само email)
- Хеширане на паролата с bcrypt (cost = 12)
- Създаване на user с
provider = "email",email_verified = FALSE - Генериране на verification token (32 random bytes -> hex)
- Запазване на
sha256(token)вemail_tokensсkind = "verify",expires_at = NOW() + 24h - Изпращане на verification email чрез Resend API
- Отговор:
202 Accepted
Email Verification (двустъпков процес)
За да се предотвратят email link pre-scanners (Microsoft Safe Links и др.), верификацията е двустъпкова:
Login (POST /auth/login/email)
POST /auth/login/email
{
"email": "user@example.com",
"password": "password123",
"cf-turnstile-response": "turnstile_token"
}
Поток:
- Валидация на Turnstile token
- Търсене на user с
provider = 'email'и подадения email - Ако user не е намерен -- dummy bcrypt compare (timing-safe) ->
ErrBadCredentials - bcrypt compare на паролата
- Проверка дали
email_verified = TRUE-> ако не:ErrNotVerified(403) - Stripe sync (ако има customer ID)
- Device limit check (за free users)
- Издаване на JWT
Password Reset
Reset token: Изтича след 1 час (за разлика от verification token-а -- 24 часа).
Cloudflare Turnstile Bot Protection
Turnstile се интегрира в login страницата и се изисква за:
POST /auth/registerPOST /auth/login/email
Поведение по среди:
- Production (
GIN_MODE=release):TURNSTILE_SECRET_KEYе задължителен; заявки без валиден token се отхвърлят - Development: Ако
TURNSTILE_SECRET_KEYе празен, валидацията се пропуска
Валидацията се извършва server-side чрез POST заявка към https://challenges.cloudflare.com/turnstile/v1/siteverify.
Device Account Limiting
За предотвратяване на злоупотреба, free потребители имат ограничение за брой отделни акаунти от едно устройство.
Конфигурация:
DEVICE_ACCOUNTS_MAX-- максимален брой акаунти per device (default: 2)COOLDOWN_HOURS-- прозорец за броене (default: 5 часа)
Redirect URI Validation
Redirect URI-тата се валидират срещу конфигурирани prefix-и (ALLOWED_REDIRECT_URIS):
- Проверява се scheme, host (exact match), port (ако е зададен) и path prefix
- В development mode (без конфигурирани prefix-и) се позволяват всички
http://иhttps://URI-та - Защита срещу prefix spoofing: валидацията е на host boundary, не на string prefix