Карта / JWT и роли / Access / refresh

Access / refresh

JWT (JSON Web Token) — самодостаточный токен: сервер не хранит состояние сессии, вся информация о пользователе зашита в сам токен. В отличие от session ID (который — просто ключ к хранилищу на сервере), JWT содержит данные прямо внутри и подписан сервером.

Структура JWT: три части через точку: header.payload.signature

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIiwicm9sZXMiOlsiVVNFUiJdLCJleHAiOjE3MDAwMDAwMDB9.XYZ
  ↑ алгоритм подписи      ↑ данные (userId, roles, срок действия)                                   ↑ подпись

Payload декодируется любым base64-декодером и виден всем — не хранить там секретов (пароль, платёжные данные). Но изменить нельзя без знания секрета — подпись сломается.

Access token — короткоживущий (15 мин — 1 час), предъявляется при каждом запросе к API:

Authorization: Bearer eyJhbGci...

Refresh token — долгоживущий (дни/недели), хранится безопасно (HttpOnly cookie), используется только для получения нового access token:

POST /auth/refresh   { refresh_token: "..." }
← { access_token: "новый", refresh_token: "возможно тоже новый" }
Копнуть глубже

Зачем два токена, а не один долгоживущий? Access token нельзя отозвать до истечения его срока — сервер его принимает только по подписи, не проверяет по базе. Если токен украли — у злоумышленника есть доступ до истечения срока. Поэтому access token живёт коротко (ущерб минимален). Refresh token живёт долго, но используется редко (только за новым access), хранится безопасно (HttpOnly — недоступен JS), и его можно отозвать в базе (если всё же нужен logout по всем устройствам — см. тему «Rotation, revoke»).

HS256 vs RS256. HS256 — симметричная подпись одним секретным ключом: быстро, но сервер, проверяющий токены, должен знать тот же секрет что и сервер, выпускающий токены. Для монолита — нормально. RS256 — асимметричная: подписываем приватным ключом, проверяем публичным. Resource Server получает публичные ключи через JWKS-endpoint и может проверять токены без доступа к приватному ключу. Это стандарт для OAuth2 / микросервисов.

В Spring Security выдача JWT:

@Service
public class JwtService {
    private final SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());

    public String generateToken(UserDetails user) {
        return Jwts.builder()
            .subject(user.getUsername())
            .claim("roles", user.getAuthorities())
            .issuedAt(new Date())
            .expiration(new Date(System.currentTimeMillis() + 900_000)) // 15 мин
            .signWith(key)
            .compact();
    }
}
🎤 Закрыл тему, если можешь объяснить:
• что такое JWT, из чего состоит и почему payload видно но нельзя изменить;
• зачем нужны два токена (access + refresh) и чем они отличаются (если дошёл до 2-го слоя).