25 функций · OAuth 2.0 + помощники OIDC · MIT

Справочник функций xoauth2

Клиент OAuth 2.0 (RFC 6749): build.bat xoauth2 включает библиотеку. Поток кода авторизации + PKCE (RFC 7636) + обновление токенов + пять пресетов провайдеров; помощники OIDC (однократное сжигание nonce, HttpGet для JWKS, GetUserInfo). Транспорт инъектируется через xoauth2httpproc — моки прогоняют весь поток офлайн, хост может подменить любую HTTP-реализацию; в комплекте реализация на xrt net/tls/http1 (http/https, IPv6, системный или свой CA, лимит ответа 1 МБ). Сопряжение с xjwt на данных — нулевая зависимость линковки: OIDC-логин собирается из восьми строк клея на уровне скриптов.

Конфигурация и пресеты (7 функций)

xoauth2UseGithub / UseGoogle / UseWechat / UseMicrosoft / UseCustom пресеты

Инициализация одной строкой: GitHub (включая api.github.com/user), Google (OIDC: issuer + JWKS + nonce), WeChat (только OAuth, PKCE выключен), Microsoft (эндпоинты и issuer генерируются по tenant — третий owned-URL, удерживаемый клиентом и освобождаемый ClientUnit), Custom (свой xoauth2config). Пресеты несут знания о провайдере; инъекция транспорта — отдельный следующий шаг (Config.Http = ...).

void xoauth2UseGithub(xoauth2client* pClient, const char* id, const char* secret, const char* redirect);

xoauth2ConfigInit / xoauth2ClientUnit жизненный цикл

Обнуляет конфигурацию (UsePkce по умолчанию включён, AuthStyle авто); ClientUnit завершает сессию: обнуляет чувствительные state/verifier/nonce, освобождает принадлежащие пресету URL эндпоинтов и чистит конфигурацию — перед повторным использованием выполните пресет заново. tenant Microsoft длиннее 256 символов отклоняется (эндпоинты остаются NULL).

Поток входа (3 функции)

xoauth2BeginLogin вход в авторизацию

Генерирует случайный state (CSRF) и PKCE verifier/challenge (S256, с учётом UsePkce пресета), nonce при UseNonce и собирает URL авторизации (scope/redirect полностью form-кодируются). Возвращает URL (xrtFree) — перенаправьте туда браузер пользователя.

char* xoauth2BeginLogin(xoauth2client* pClient);

xoauth2CompleteLogin обмен кода

Сравнение state за константное время (при совпадении сжигается, защита от повтора) → сборка запроса токена (AuthStyle=BODY кладёт полностью закодированные учётные данные в тело; =BASIC шлёт заголовок Authorization) → сжигание verifier → POST через транспортный колбэк → градуированный разбор ответа. Успех — токен (освободить xoauth2TokenFree). После несовпадения state нужен новый BeginLogin.

xoauth2token* xoauth2CompleteLogin(xoauth2client* pClient, const char* sCode, const char* sState);
Пример · вход через GitHub в три шага
xoauth2client oauth;
xoauth2UseGithub(&oauth, sClientId, sSecret, "https://app.example/cb");
oauth.Config.Http = xoauth2HttpXrt;          /* инъекция транспорта */
oauth.Config.HttpContext = pHttp;            /* дескриптор из xoauth2HttpXrtCreate */

char* url = xoauth2BeginLogin(&oauth);      /* 302 на страницу авторизации */
/* ...пользователь авторизуется; колбэк с code + state... */
xoauth2token* tok = xoauth2CompleteLogin(&oauth, sCode, sState);
if ( tok ) {
    /* tok->AccessToken / RefreshToken / ExpiresAt */
    xoauth2TokenFree(tok);                   /* чувствительные поля уже обнулены */
}

xoauth2TokenFree освобождение

Освобождает токен — открытый текст access/refresh/id токенов beforehand обнуляется.

Управление токенами (2 функции)

xoauth2Refresh обновление

Собирает запрос grant_type=refresh_token, прогоняет через транспорт и разбирает градуированный ответ (AuthStyle как в CompleteLogin). Старый токен освобождает вызывающий. Четыре уровня ошибок: NETWORK (соединение/таймаут/TLS) → TOKEN_ENDPOINT (ошибочный HTTP-статус) → TOKEN_DENIED (поле error от провайдера) → TOKEN_RESPONSE (сбой разбора тела при 2xx).

xoauth2token* xoauth2Refresh(xoauth2client* pClient, const char* sRefreshToken);

xoauth2TokenExpiring проверка истечения

Сверяет ExpiresAt с текущими часами: истечёт ли токен в течение leewaySeconds. Если провайдер не вернул expires_in (например, GitHub) — считается неистекающим: неизвестный срок ≠ вот-вот истечёт, и у таких токенов обычно нет refresh_token.

Помощники OIDC (3 функции, слой сопряжения на данных)

xoauth2HttpGet универсальный GET

Выполняет GET через транспортный колбэк клиента для любого URL и возвращает текст тела ответа (xrtFree). Типичное применение — загрузка JWKS JSON. Градуировка ошибок как при обмене токена.

char* xoauth2HttpGet(xoauth2client* pClient, const char* sUrl, const char* sAuthHeader, int* piStatus);

xoauth2NonceConsume потребление nonce

Сравнение за константное время с nonce, сгенерированным BeginLogin; при совпадении сжигается (однократно, защита от повтора) и возвращается true; несовпадение устанавливает XOAUTH2_ERROR_NONCE_MISMATCH.

xoauth2GetUserInfo данные пользователя

GET UserInfoUrl с Authorization: Bearer (динамическое выделение — длинные токены не обрезаются), возвращает объект claims (не-объектный JSON отклоняется). Также верный путь для не-OIDC провайдеров (например, WeChat /sns/userinfo).

xvalue* xoauth2GetUserInfo(xoauth2client* pClient, const char* sAccessToken);
Пример · восьмистрочный клей с xjwt
xoauth2token* tok = xoauth2CompleteLogin(&oauth, code, state);

int st;
char* jwksJson = xoauth2HttpGet(&oauth, oauth.Config.JwksUrl, NULL, &st);
xjwtjwks* keys = xjwtJwksParse(jwksJson);        /* строка на входе */
xjwtcheck ck;  xjwtCheckInit(&ck);
ck.Issuer = oauth.Config.Issuer;               /* знание пресета — просто строка */
ck.Audience = oauth.Config.ClientId;
xvalue* claims = xjwtVerifyJwks(tok->IdToken, keys, &ck);

char nonce[128];
xjwtClaimString(claims, "nonce", nonce, sizeof(nonce));
xoauth2NonceConsume(&oauth, nonce);            /* константное время + сжигание */

Транспорт из комплекта (5 функций)

xoauth2HttpXrtInit / xoauth2HttpXrtUnit стековый вариант

Создаёт или заимствует net engine + верификатор системного/своего CA + таймаут (по умолчанию 15 с). Для C-хостов со стековым объявлением.

xoauth2HttpXrtCreate / xoauth2HttpXrtDestroy кучный вариант

Дескриптор в куче — когда непрозрачную структуру нельзя объявить на стеке (естественный путь для уровня скриптов). Параметры как у Init.

xoauth2httpxrt* xoauth2HttpXrtCreate(void* pBorrowedEngine, const char* sCaPem, uint64_t uTimeoutUs);

xoauth2HttpXrt транспортный колбэк

Два метода POST/GET (POST с form-заголовками, GET без заголовков сущности; Authorization передаётся в обоих), схемы http/https, литералы IPv6, будущий TLS/TCP-ввод-вывод, сборка и разбор http1 из xrt, лимит тела ответа 1 МБ. Подключается на Config.Http.

Утилиты и ошибки (5 функций)

xoauth2PkceGenerate / xoauth2StateGenerate / xoauth2UrlEncode офлайн-инструменты

PKCE code_verifier (случайные 43 символа) + challenge (BASE64URL(SHA256(verifier)), воспроизводимо проверяется); случайный state (URL-safe); процентное кодирование URL — всё доступно офлайн для тестов и нестандартных сценариев.

xoauth2LastError чтение ошибки

Возвращает код ошибки домена xoauth2 (XOAUTH2_ERROR_*, восемь значений), 0 для чужих доменов. Читайте сразу после сбоя. Четыре уровня прямо отображаются на семантику HTTP: STATE_MISMATCH→400, TOKEN_DENIED→401, ENDPOINT/RESPONSE→502, NETWORK→504.

Базовая безопасность: однократное сжигание state/nonce за константное время, сжигание verifier после использования, полное form-кодирование тела запроса, Basic-заголовок по RFC 6749 §2.3.1, обнуление полей токена перед освобождением, отклонение нецелого expires_in. 166+15 тестов (полные мок-пути, реальный loopback end-to-end, регрессия сопряжения с xjwt). Полный исходник — lib/xoauth2; сопрягается на данных с xjwt (без requires — библиотеки не знают друг о друге).