# jose: JWT, подпись, claims и ключи

Настоящий jose 6.2.17 и Web Crypto. Девять тем, 22 варианта. Браузер создаёт две пары ES256 в памяти, подписывает и проверяет учебные JWT. Приватные CryptoKey неэкспортируемые и не сохраняются. Код не читает localStorage, не отправляет токены в сеть и не принимает реальные секреты. Тип токена at+jwt в лаборатории — явная метка проверки, а не заявление о полном соответствии профилю OAuth access token.

Нужен Node.js 24 LTS >=24.15.0. Зависимости закреплены package-lock.json. Bootstrap 5.3.9 локальный. Только открытый код MIT.

## Windows / PowerShell

```powershell
npm ci --ignore-scripts
npm test
npm run demo
npm run build
# Готовую public раздайте локальным HTTP-сервером, например при установленном PHP:
php -S 127.0.0.1:8522 -t public
# http://127.0.0.1:8522 ; остановка Ctrl+C
```

HTTPS или localhost необходимы для Web Crypto. Простое открытие index.html через file:// не подходит. Готовая public уже собрана; для повторной сборки/тестов Node.js нужны npm ci и Node. Сборка esbuild использует установленный платформенный пакет npm; загрузочные install scripts отключены.

## Linux

Установите поддерживаемый Node 24 LTS из официального источника, проверьте node --version и npm --version. На Ubuntu/Debian PHP CLI можно использовать только как просмотрщик готовой статики:

```bash
npm ci --ignore-scripts
npm test
npm run demo
npm run build
php -S 127.0.0.1:8522 -t public
```

На VPS статическую public можно раздать существующим Nginx/Caddy по HTTPS. Для реального API инструкции ниже и docs/LINUX-VPS.md. Публичная мастерская не обращается к localhost посетителя и не выдаёт результат локальной функции за выполненный HTTP-запрос.

## Реальный Node API, отдельный процесс

```powershell
npm run api
# API привязан только к 127.0.0.1:8523.
```

В другом PowerShell:

```powershell
$demo = Invoke-RestMethod 'http://127.0.0.1:8523/demo-token?mode=valid'
Invoke-RestMethod 'http://127.0.0.1:8523/report' -Headers @{Authorization="Bearer $($demo.token)"}
# mode=forbidden выдаёт подпись с недостаточным scope → 403.
# mode=expired выдаёт истёкший токен → 401.
# Отсутствующий токен → 401.
```

Bash с curl и Node для извлечения JSON:

```bash
token=$(curl -fsS 'http://127.0.0.1:8523/demo-token?mode=valid' | node -e 'let s=""; process.stdin.on("data",c=>s+=c).on("end",()=>process.stdout.write(JSON.parse(s).token));')
curl -i -H "Authorization: Bearer $token" http://127.0.0.1:8523/report
unset token
```

Эти токены вымышленные. `/demo-token` не проверяет пароль: это открытый локальный генератор фикстур, не система входа. Не публикуйте его как production-auth. API хранит ключи только в памяти, после перезапуска старые токены перестанут проходить проверку. GET /jwks возвращает только публичные части; GET /health показывает готовность; неизвестные маршруты — 404, неподходящий метод — 405.

## Часы и варианты

В браузерных опытах используется фиксированное время 2026-11-01T08:00:00Z, чтобы отрицательные случаи не менялись после даты публикации. В API берётся настоящее Date.now(). Подписи и ключи всё равно новые при каждом открытии. Поэтому строки токенов различаются между запусками; сравнивайте статус и причины, а не сами подписи.

Темы: decode; подпись; подмена; exp/nbf/clockTolerance; iss/aud; список разрешённых algorithms; публичный JWK; локальный доверенный JWKS и ротация; отдельная функция проверки scope: 401/403/200. Все запросы Node API проверяются настоящим loopback HTTP в node:test. В браузерной девятой теме проверка подписи настоящая, HTTP-статус — модель решения этой же функции.

## Исходники

- src/lab.mjs — криптография и 22 варианта; никакого eval.
- src/api.mjs — реальный HTTP API.
- src/browser.mjs — интерфейс и безопасный textContent.
- tests/ — криптографические проверки и HTTP-тесты.
- tools/demo.mjs — сводка реального выполнения Node без приватных ключей и токенов.
- public/sources.json — исходники для просмотра; public/app.js —сборка.

Не используйте decodeJwt как авторизацию. Доверенный ключ, ожидаемые issuer/audience/algorithm и право операции определяет приложение. JWT не обеспечивает автоматически logout, отзыв, защиту cookies/CSRF, секретность payload или хранение паролей. Подписанные данные здесь читаемы; JWE в этой лаборатории не реализован.

Источники: https://github.com/panva/jose ; https://github.com/panva/jose/blob/main/docs/jwt/verify/functions/jwtVerify.md ; https://github.com/panva/jose/blob/main/docs/jwks/local/functions/createLocalJWKSet.md ; https://www.rfc-editor.org/rfc/rfc8725.html .
