TikTok Login Kit: OAuth-поток и жизненный цикл токенов
TikTok Login Kit — это OAuth 2.0. Приложение отправляет пользователя на https://www.tiktok.com/v2/auth/authorize/ с client_key, scopes и state, получает code на зарегистрированный redirect URI и на сервере обменивает его через /v2/oauth/token/. Access token живёт 24 часа, refresh token — 365 дней, поэтому обновление нужно планировать ежедневно.
Обновлено:
Как работает OAuth в TikTok?
TikTok использует authorization code flow. Пользователь подтверждает запрошенные scopes на странице авторизации TikTok, TikTok перенаправляет его обратно с code, а ваш сервер обменивает код вместе с client key и client secret на access token, refresh token и open_id пользователя. Дальше API-запросы отправляют access token в заголовке Authorization: Bearer.
Login Kit есть для Web, Desktop, iOS и Android. Веб-поток опирается на сервер, который хранит client secret и проверяет state; в desktop- и mobile-потоках добавляется PKCE — при обмене кода отправляется code_verifier.
Что может токен, определяют scopes. user.info.basic добавляется автоматически; остальные, например video.list или video.publish, нужно подключить к приложению в портале разработчика и показать на проверке приложения.
Ключевые термины: client key, client secret, open_id и токены
- client_key
- Открытый идентификатор приложения. Передаётся в ссылке авторизации и в запросах токена.
- client_secret
- Секретный ключ приложения. Используется только в серверных запросах к
/v2/oauth/token/и/v2/oauth/revoke/; не попадает в браузер или мобильную сборку. - code
- Код авторизации, который приходит на redirect URI после согласия пользователя. Обменивайте его на токены сразу.
- access_token
- Bearer-токен для API-запросов, действует 24 часа с момента выдачи.
- refresh_token
- Нужен для получения нового access token; действует 365 дней с первой выдачи. В ответе на обновление может прийти другой refresh token.
- open_id
- Уникальный идентификатор пользователя TikTok, приходит вместе с токеном. Используйте его как ключ подключённого аккаунта.
- state
- Случайное значение, которое создаётся перед редиректом и сверяется в callback, — защита от CSRF.
Как настроить OAuth TikTok для веб-приложения
Зарегистрируйте redirect URI
В настройках Login Kit добавьте до 10 redirect URI. Каждый должен быть абсолютным, начинаться с
https, быть короче 512 символов, статическим (без query-параметров) и без фрагмента#.Создайте и сохраните state
Для каждой попытки входа генерируйте случайную строку и храните её в сессии пользователя или короткоживущем cookie. Официальный веб-пример TikTok тоже использует короткоживущий cookie.
Перенаправьте на страницу авторизации
Откройте
https://www.tiktok.com/v2/auth/authorize/сclient_key,response_type=code,scopeчерез запятую,redirect_uriиstate. Чтобы окно согласия показывалось всегда, добавьтеdisable_auto_auth=1.Проверьте callback
TikTok возвращает
code,scopesиstate, а при ошибке —errorиerror_description. Отклоняйте запрос, еслиstateне совпал, и сверяйте выданныеscopesс запрошенными.Обменяйте код на сервере
Отправьте POST на
https://open.tiktokapis.com/v2/oauth/token/в форматеapplication/x-www-form-urlencodedсclient_key,client_secret,code,grant_type=authorization_codeи тем жеredirect_uri. Desktop- и mobile-приложения передают ещёcode_verifier.Надёжно сохраните токены
Храните
access_token,refresh_token, оба срока иopen_idв зашифрованном виде. Веб-гайд TikTok прямо возлагает на сервер ответственность за безопасность client secret и refresh token.
Login Kit на Python
Обработчики не привязаны к фреймворку: session — хранилище сессии вашего веб-фреймворка.
import secrets
from socialift import TikTok
REDIRECT_URI = "https://app.example.com/oauth/tiktok/callback"
SCOPES = ["user.info.basic", "video.list", "video.publish"]
async def begin_login(session: dict) -> str:
session["tiktok_state"] = secrets.token_urlsafe(32)
async with TikTok.from_env() as tt:
return tt.login_url(
redirect_uri=REDIRECT_URI,
state=session["tiktok_state"],
scopes=SCOPES,
)
async def finish_login(session: dict, code: str, state: str) -> dict:
expected = session.pop("tiktok_state", "")
if not expected or not secrets.compare_digest(state, expected):
raise ValueError("OAuth state mismatch")
async with TikTok.from_env() as tt:
bundle = await tt.exchange_code(code, redirect_uri=REDIRECT_URI)
return {
"open_id": bundle.raw.get("open_id"),
"access_token": bundle.access_token,
"refresh_token": bundle.refresh_token,
"expires_at": bundle.expires_at,
"scopes": bundle.scopes,
}exchange_code отправляет тело в формате form-urlencoded, как требует TikTok, и выбрасывает ApiError, если access token не пришёл.
Сохраняйте результат в зашифрованном виде. SDK ничего не хранит между вызовами, поэтому один клиент может обслуживать много авторов.
PKCE: веб, desktop и mobile
| Платформа | PKCE | Правила redirect URI |
|---|---|---|
| Web | В гайде Login Kit for Web не упоминается; защита строится на серверном secret и state | Абсолютный https, статический, без фрагмента, до 10 штук, короче 512 символов |
| Desktop | Обязателен: code_challenge и code_challenge_method=S256 в ссылке, code_verifier при обмене | http или https, допускаются localhost и 127.0.0.1, порт обязателен (можно wildcard), без параметров и фрагмента |
| iOS / Android | code_verifier обязателен при обмене кода | По данным платформы, указанным для приложения (package name, bundle ID) |
Desktop-гайд TikTok вычисляет code_challenge как SHA-256 от verifier в hex-кодировке, а не в base64url, как в RFC 7636.
PKCE для desktop-приложений
Verifier должен быть длиной 43–128 символов и состоять только из A–Z, a–z, 0–9 и символов -, ., _, ~.
import hashlib
import secrets
from socialift import TikTok
REDIRECT_URI = "http://127.0.0.1:3455/callback/"
def make_pkce() -> tuple[str, str]:
verifier = secrets.token_urlsafe(48) # 64 символа
challenge = hashlib.sha256(verifier.encode()).hexdigest() # hex, как в документации TikTok
return verifier, challenge
async def desktop_login(state: str) -> tuple[str, str]:
verifier, challenge = make_pkce()
async with TikTok.from_env() as tt:
url = tt.login_url(
redirect_uri=REDIRECT_URI,
state=state,
code_challenge=challenge,
code_challenge_method="S256",
)
return url, verifier
async def desktop_callback(code: str, verifier: str):
async with TikTok.from_env() as tt:
return await tt.exchange_code(code, redirect_uri=REDIRECT_URI, code_verifier=verifier)Обмен кода выполняйте на своём backend: запрос токена всё равно содержит client secret.
Сроки жизни токенов и что с ними делать
| Ситуация | Срок | Что делать |
|---|---|---|
access_token | 24 часа с момента выдачи | Обновляйте до истечения; точное значение — в expires_in ответа |
refresh_token | 365 дней с первой выдачи | Если в ответе на обновление пришёл другой refresh token, замените сохранённый |
| Истёк refresh token | нет | Проведите пользователя через Login Kit заново |
| Пользователь отключил приложение | К приходу authorization.removed access token уже недействителен | Пометьте аккаунт отключённым и прекратите запросы |
Вызван /v2/oauth/revoke/ | Доступ вашего приложения отозван | Удалите сохранённые токены |
естьнет
Ежедневное обновление и отзыв при отключении
from datetime import datetime, timedelta, timezone
from socialift import ApiError, TikTok
async def ensure_fresh(account: dict) -> dict:
left = account["expires_at"] - datetime.now(timezone.utc)
if left > timedelta(hours=2):
return account
async with TikTok.from_env() as tt:
try:
bundle = await tt.refresh_token(account["refresh_token"])
except ApiError:
account["status"] = "reconnect_required"
return account
account.update(
access_token=bundle.access_token,
refresh_token=bundle.refresh_token or account["refresh_token"],
expires_at=bundle.expires_at,
)
return account
async def disconnect(account: dict) -> None:
async with TikTok.from_env() as tt:
await tt.revoke(account["access_token"])Запускайте обновление через cron или очередь с интервалом меньше 24 часов. Каждый раз сохраняйте refresh token из ответа — TikTok требует использовать новое значение, если оно изменилось.
Scopes и согласие на практике
Параметр scope — список через запятую, и каждый scope должен быть заранее назначен приложению на сайте TikTok for Developers. В callback TikTok возвращает выданные scopes в параметре scopes — сохраните его и проверяйте перед вызовом endpoint'а, которому нужен конкретный scope.
Если вы позже добавили scopes, проведите существующих пользователей через авторизацию снова. При disable_auto_auth=0 TikTok пропускает страницу авторизации для активной сессии, при disable_auto_auth=1 показывает её всегда — именно это нужно, когда меняется набор scopes. В SDK: tt.login_url(..., disable_auto_auth=True).
Если пользователь удалит приложение в настройках TikTok, зарегистрированный webhook получит authorization.removed; к этому моменту access token уже недействителен. Socialift SDK проверяет такие доставки через verify_tiktok_request и разбирает через parse_tiktok_event. Точные redirect- и webhook-URL для консоли TikTok показаны на странице «Kalitlar» (ключи) в кабинете Socialift.
Чек-лист безопасности OAuth TikTok
- Храните client secret и refresh token только на сервере и в зашифрованном виде.
- Создавайте новый
stateдля каждого входа и отклоняйте callback с несовпадающим значением. - Регистрируйте точные статические HTTPS redirect URI; контекст передавайте через state или сессию, а не query-параметрами.
- В desktop-приложениях используйте PKCE с
S256и передавайтеcode_verifierпри обмене. - Обновляйте access token по расписанию чаще, чем раз в 24 часа, и сохраняйте сменившиеся refresh token.
- Отзывайте токен через
/v2/oauth/revoke/, когда пользователь отключается в вашем продукте. - Пишите в лог
log_idнеудачных запросов для поддержки TikTok.
Частые вопросы
Сколько действует access token TikTok?
Access token действует 24 часа с момента выдачи, refresh token — 365 дней с первой выдачи. Поэтому интеграции нужна ежедневная задача обновления; после истечения refresh token пользователь проходит авторизацию заново.
Возвращает ли TikTok новый refresh token при обновлении?
Может вернуть. По документации TikTok refresh_token в ответе может отличаться от отправленного, и тогда нужно использовать новое значение. Обновляйте сохранённый токен после каждого обновления.
Нужен ли PKCE для веб-авторизации TikTok?
В гайде Login Kit for Web PKCE нет: веб-поток опирается на серверный client secret и проверку state. Desktop- и mobile-приложения обязаны передавать code_verifier при обмене кода; для desktop code_challenge — это SHA-256 в hex.
Почему возникает ошибка redirect_uri?
redirect_uri в запросе должен в точности совпадать со значением, зарегистрированным в настройках приложения. Для веба это абсолютный https-адрес, статический (без параметров) и без фрагмента #; при обмене кода передавайте то же значение.
Как отозвать токен TikTok?
Отправьте POST на https://open.tiktokapis.com/v2/oauth/revoke/ с client_key, client_secret и token. В Socialift SDK это await tt.revoke(access_token).
Какой scope выдаётся по умолчанию?
Приложениям с Login Kit автоматически добавляется user.info.basic: он даёт open_id, аватар и отображаемое имя. Остальные scopes подключаются к приложению отдельно.