Аутентификация

Один заголовок в каждом запросе, кроме самоописания API.

Authorization: Bearer <your api key>

Токены выпускаются на странице профиля - до десяти на аккаунт, и каждый отзывается отдельно, так что утёкший токен можно удалить, не трогая остальные. Нужен платный тариф: без него все эндпоинты, кроме / и /v1/account, отвечают 403 plan_required.

Приложение может получить токен за вас и через OAuth 2.1: вы входите, видите, что оно запрашивает, и нажимаете «Разрешить». Его токен передаётся в том же заголовке и работает так же.

Почему не ?key=

Ключ в строке запроса оказывается там, куда вы его не клали: в журналах доступа веб-сервера, в истории браузера, в журналах прокси и в заголовке Referer любого ресурса, на который ссылается ответ. Поэтому API его не принимает и отвечает 401 missing_key с объяснением.

Старые адреса ?export= на основном сайте по-прежнему принимают ?key=: от этого зависят скрипты, написанные годы назад, и отказ от него их сломал бы. Это единственное место, где он остался, - см. старые адреса выгрузки.

Как проверить ключ

/v1/account - самый дешёвый вызов: он не расходует лимит и работает даже на аккаунте без тарифа, поэтому отвечает сразу на два вопроса: «действителен ли ключ» и «что мне положено».

curl -H "Authorization: Bearer $KEY" https://api.publicwww.com/v1/account
{
  "plan": "enterprise",
  "plan_until": 1819461840,
  "full_access": true,
  "quota": {
    "searches": { "limit": 300, "used": 12, "resets_at": 1787961600 },
    "snippets": { "limit": 100, "used": 3,  "resets_at": 1787961600 }
  },
  "limits": {
    "disclosed_positions": 4294967295,
    "max_per_page": 1000000,
    "max_per_page_snippets": 10000
  }
}

Что может пойти не так

СтатусКодЧто означает
401missing_keyНет заголовка Authorization: Bearer. Ключ в строке запроса не считается.
401invalid_keyКлюч не принадлежит ни одному аккаунту. Проверьте, не попал ли в него лишний перевод строки или кавычка.
403plan_requiredС ключом всё в порядке, но у аккаунта нет платного тарифа.

Ответ 401 также содержит заголовок WWW-Authenticate: Bearer, чтобы HTTP-клиенты с универсальной обработкой аутентификации вели себя разумно.

OAuth 2.1 для приложений

Приложение, которое работает от имени других людей, - ассистент, интеграция, облачный сервис - не должно просить каждого из них копировать токен. Вместо этого оно отправляет их в PublicWWW: они входят, одобряют приложение, и оно получает собственный токен. Этот токен передаётся как Authorization: Bearer, как и любой другой, и открывает весь API и MCP-сервер по адресу https://api.publicwww.com/mcp - в пределах тарифа, лимитов и ограничения частоты этого аккаунта.

ЧтоГде
Метаданные сервера авторизации (RFC 8414)https://publicwww.com/.well-known/oauth-authorization-server
Метаданные защищённого ресурса (RFC 9728)https://api.publicwww.com/.well-known/oauth-protected-resource
Эндпоинт авторизацииhttps://publicwww.com/oauth/authorize
Эндпоинт токеновhttps://publicwww.com/oauth/token
Эндпоинт отзыва (RFC 7009)https://publicwww.com/oauth/revoke

Как опознаётся приложение

Регистрации клиентов нет. client_id - это https-адрес небольшого JSON-документа, который публикует само приложение, - документа метаданных клиента. PublicWWW читает его при каждом подключении, поэтому название и адреса возврата всегда актуальны, а тот, кто одобряет доступ, видит, какой хост их опубликовал.

{
  "client_id": "https://app.example.com/oauth/client.json",
  "client_name": "Example App",
  "redirect_uris": ["https://app.example.com/oauth/callback"],
  "grant_types": ["authorization_code"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}
  • client_id внутри документа должен в точности совпадать с адресом, по которому документ отдаётся. Документ загружается по https, с адреса с путём, без перехода по редиректам; он должен отвечать не дольше 5 секунд и весить меньше 64 КБ.
  • redirect_uris - это https-адреса или http на 127.0.0.1, localhost либо [::1] для приложения, которое работает на компьютере самого человека, - там подходит любой порт. Собственные схемы вроде myapp:// не принимаются.
  • Любое приложение - публичный клиент: запрос токена не содержит секрета, какой бы token_endpoint_auth_method ни был указан в документе. Код авторизации вместо этого защищён PKCE.

Порядок действий

Authorization code с PKCE; единственный метод - S256. Отправьте человека на эндпоинт авторизации:

https://publicwww.com/oauth/authorize
    ?response_type=code
    &client_id=https%3A%2F%2Fapp.example.com%2Foauth%2Fclient.json
    &redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fcallback
    &code_challenge=<BASE64URL(SHA-256(code_verifier))>
    &code_challenge_method=S256
    &state=<random>

Если человек ещё не вошёл, он входит по коду из письма, видит название приложения, хост его документа и куда он вернётся, и нажимает «Разрешить» или «Отклонить». На redirect_uri возвращаются code, ваш state и iss=https://publicwww.com (RFC 9207). Код действует десять минут и срабатывает один раз. Обменяйте его:

curl https://publicwww.com/oauth/token \
     -d grant_type=authorization_code \
     -d code="$CODE" \
     -d code_verifier="$VERIFIER" \
     -d client_id=https://app.example.com/oauth/client.json \
     -d redirect_uri=https://app.example.com/oauth/callback
{ "access_token": "<token>", "token_type": "Bearer", "scope": "mcp" }

scope можно не указывать: область действия одна, mcp, и она покрывает весь API. resource (RFC 8707) тоже можно не указывать; если он передан, то это https://api.publicwww.com/mcp или https://api.publicwww.com.

Сколько живёт токен

Пока его не отзовут: срока действия нет, и refresh-токена тоже нет. Интеграция, которая работает сегодня, будет работать и завтра, и никому не придётся её трогать. Токен отзывается только намеренно: человек отключает приложение на странице профиля, приложение само отзывает токен или аккаунт удаляется.

curl https://publicwww.com/oauth/revoke \
     -d token="$TOKEN" \
     -d client_id=https://app.example.com/oauth/client.json

Эндпоинт отзыва всегда отвечает 200 - независимо от того, существовал ли токен.

Ошибки OAuth

ГдеКодЧто означает
Авторизациястраница ошибкиДокумент по client_id не удалось прочитать, или в нём нет redirect_uri. Человека обратно не отправляют: по непроверенному адресу переход не выполняется никогда.
Авторизацияinvalid_requestНет code_challenge или метод отличен от S256.
Авторизацияunsupported_response_typeЧто угодно, кроме response_type=code.
Авторизация, токенinvalid_targetresource, отличный от API.
Авторизацияaccess_deniedЧеловек нажал «Отклонить».
Токенinvalid_grantКод неизвестен, уже использован, истёк или выдан другому client_id; либо не совпадают code_verifier или redirect_uri.
Токенunsupported_grant_typeЧто угодно, кроме authorization_code.

Ошибки авторизации, кроме страницы ошибки, возвращаются на redirect_uri в виде error, error_description, state и iss; ошибки токена - это ответ 400 с теми же двумя полями в JSON.

Далее Запросы