Аутентификация
Один заголовок в каждом запросе, кроме самоописания 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
}
}
Что может пойти не так
| Статус | Код | Что означает |
|---|---|---|
| 401 | missing_key | Нет заголовка Authorization: Bearer. Ключ в строке запроса не считается. |
| 401 | invalid_key | Ключ не принадлежит ни одному аккаунту. Проверьте, не попал ли в него лишний перевод строки или кавычка. |
| 403 | plan_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_target | resource, отличный от 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.