Ответ
Основной и рекомендуемый способ — использование JWKS (JSON Web Key Set). Это стандартный механизм, который позволяет клиентам динамически получать публичные ключи для проверки подписи JWT.
1. JWKS (JSON Web Key Set) — Стандартный подход
Это публичный эндпоинт (например, /.well-known/jwks.json), который возвращает JSON-объект с набором ключей. Такой подход позволяет серверу аутентификации ротировать ключи без необходимости вносить изменения в клиентские приложения.
Пример ответа JWKS:
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"kid": "unique-key-id-1",
"alg": "RS256",
"n": "...base64url-encoded-modulus...",
"e": "AQAB"
}
]
}
kty: Тип ключа (например,RSA).use: Назначение ключа (sig— для подписи).kid: Уникальный идентификатор ключа. JWT в своем заголовке содержитkid, чтобы клиент знал, какой именно ключ из набора использовать для верификации.
2. Другие способы (менее гибкие)
- Встраивание в конфигурацию клиента: Публичный ключ жестко прописывается в конфигурации клиентского приложения. Главный минус — при смене ключа на сервере требуется обновление всех клиентов.
- Передача в заголовке JWT (
jwk): Публичный ключ встраивается непосредственно в заголовок токена. Используется редко, так как значительно увеличивает размер токена.
Пример получения ключа из JWKS на Python:
import jwt
import requests
# URL эндпоинта с ключами
jwks_url = "https://auth.example.com/.well-known/jwks.json"
# Получаем JWT, который нужно проверить
token = "eyJhbGciOiJSUzI1NiIsImtpZCI6InVuaXF1ZS1rZXktaWQtMSJ9..."
# 1. Получаем kid из заголовка токена
header = jwt.get_unverified_header(token)
kid = header['kid']
# 2. Загружаем ключи с JWKS-эндпоинта
jwks_client = jwt.PyJWKClient(jwks_url)
signing_key = jwks_client.get_signing_key_from_jwt(token)
# 3. Верифицируем токен с помощью найденного ключа
data = jwt.decode(
token,
signing_key.key,
algorithms=["RS256"],
options={"verify_aud": False}
)
print(data) Ответ 18+ 🔞
Давай разберём, как серверы обычно отдают свои публичные ключи для проверки JWT, чтобы клиенты могли понять, не подделан ли токен. А то ведь, блядь, любой распиздяй может нарисовать себе токен в блокноте и кричать, что он — король интернета.
1. JWKS (JSON Web Key Set) — Правильный, ебать, подход
Это самый ахуенный и стандартный способ. Сервер аутентификации выставляет на всеобщее обозрение специальный эндпоинт, типа /.well-known/jwks.json. Туда любой желающий (клиент) может прийти и забрать свежие публичные ключи. Главная фишка — сервер может менять свои ключи (ротировать), а клиентам даже не нужно будет перезапускаться, они просто в следующий раз возьмут новый ключ из этого набора. Умно, сука!
Как выглядит этот ответ:
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"kid": "unique-key-id-1",
"alg": "RS256",
"n": "...base64url-encoded-modulus...",
"e": "AQAB"
}
]
}
Смотри, что тут есть:
kty: Тип ключа. ОбычноRSA, но бывают и другие, епта.use: Зачем ключ.sig— значит для подписи, а не для шифрования.kid: Уникальный ид ключа. Это, блядь, самое важное! Когда сервер подписывает JWT, он в заголовок токена пишет этот самыйkid. Клиент смотрит в токен, видитkid, потом лезет в JWKS, находит ключ с таким жеkid— и вуаля, он знает, каким ключом проверять подпись. Красота, в рот меня чих-пых!
2. Другие способы (которые обычно — говно)
- Зашить ключ в клиент намертво. Берешь публичный ключ и пишешь его прямо в конфиг своего приложения. Минус, блядь, очевиден: если на сервере ключ поменяют, то все твои клиенты разом накроются медным тазом, пока ты не обновишь конфиг у каждого. Пиздец, а не подход.
- Засунуть ключ прямо в заголовок JWT. Да, можно и так, поле
jwkназывается. Но это увеличивает размер токена до овердохуища, поэтому так почти не делают.
Ну и как это всё на Python выглядит, пример:
import jwt
import requests
# Адрес, где лежат ключи
jwks_url = "https://auth.example.com/.well-known/jwks.json"
# Токен, который нам прислал какой-то чувак и который надо проверить
token = "eyJhbGciOiJSUzI1NiIsImtpZCI6InVuaXF1ZS1rZXktaWQtMSJ9..."
# 1. Смотрим, не обманывают ли нас. Вытаскиваем заголовок токена без проверки.
header = jwt.get_unverified_header(token)
kid = header['kid'] # Выцепляем идентификатор ключа (kid)
# 2. Идём на сервер и качаем актуальные ключи
jwks_client = jwt.PyJWKClient(jwks_url)
signing_key = jwks_client.get_signing_key_from_jwt(token)
# 3. А теперь, сука, проверяем токен этим ключом!
data = jwt.decode(
token,
signing_key.key,
algorithms=["RS256"],
options={"verify_aud": False}
)
print(data) # Если не вылетела ошибка — токен валидный, можно работать с данными внутри.
Вот так, блядь, и живём. Сервер крутит ключами, а клиенты их сами подтягивают. Никакой магии, один стандарт и немного кода.