Logo
Overview

OAuth и JWT для REST API: авторизация на пальцах

April 24, 2026
8 min read

Почему пароль в каждом запросе — это как отдать ключи от квартиры курьеру «на всякий случай»

Если вы когда-нибудь проектировали REST API и упирались в вопрос «а как мы тут поймём, что это вообще клиент Вася, а не хакер Петя?» — поздравляю, вы дошли до темы авторизации. И первое, что всплывает в гугле, — это буквенный салат: OAuth, OAuth 2.0, JWT, Bearer, OIDC, SAML. Половина слов звучит одинаково, вторая половина — как заклинания из Hogwarts Legacy.

Давайте разберёмся, что из этого что, и почему OAuth и JWT почти всегда идут в паре (хотя в теории не обязаны).

Аутентификация vs авторизация: два слова, которые все путают

Прежде чем лезть в OAuth, разложим два термина, которые путают даже в тендерной документации крупных банков.

Аутентификация (authentication) — это «кто вы?». Проверка, что пользователь тот, за кого себя выдаёт (логин/пароль, биометрия, SMS-код).

Авторизация (authorization) — это «что вам можно?». Проверка, имеет ли уже опознанный пользователь право совершить действие (читать заказы, списывать деньги, удалять юзеров).

Условно: охранник на входе в офис смотрит пропуск — это аутентификация. Турникет пускает вас только на 3-й этаж — это авторизация. OAuth, несмотря на название, — это в первую очередь про авторизацию (передачу прав между сервисами), хотя часто используется как часть системы входа.

Если хотите освежить, чем REST API отличается от всего остального и почему он stateless — у меня есть отдельный пост про основные принципы REST API и про stateless vs stateful на пальцах. Вся логика токенов ниже построена именно на stateless-модели.

Что такое OAuth 2.0 и зачем он появился

OAuth 2.0 — это протокол делегированной авторизации. Ключевое слово тут — «делегированной». Когда сервис А хочет получить данные пользователя из сервиса Б, пользователь не даёт сервису А свой логин и пароль от Б. Вместо этого сервис Б выдаёт сервису А временный токен с ограниченными правами.

Классический пример: приложение «Умный планировщик» хочет читать ваш Google Calendar. Без OAuth вам пришлось бы отдать планировщику свой пароль от Google (и молиться). С OAuth — Google выдаёт планировщику токен вида «можно читать календарь Паши до 15 мая, и больше ничего».

Четыре роли OAuth

В протоколе участвуют четыре действующих лица. Запомнить их проще всего через аналогию с рестораном:

Роль OAuthКто этоАналогия в ресторане
Resource OwnerПользователь, владелец данныхГость, заказавший бутылку вина
ClientПриложение, которое хочет получить данныеОфициант, который несёт вино
Authorization ServerСервер, выдающий токеныАдминистратор, проверяющий возраст гостя
Resource ServerAPI с защищёнными даннымиВинный погреб, откуда достают бутылку

Клиент (приложение) идёт к администратору (authorization server), показывает согласие гостя (resource owner), получает временный пропуск (access token) и с ним идёт в погреб (resource server) за вином. Гостя при этом никто не заставляет бегать с паролем.

Access token, refresh token и почему их два

Самая распространённая путаница — это зачем вообще два токена, если один уже работает.

Access token — короткоживущий токен (обычно 5–60 минут), которым клиент подписывает каждый запрос к API. Это «пропуск на сегодня».

Refresh token — долгоживущий токен (дни, недели, месяцы), который хранится у клиента и нужен только для одного — попросить у authorization server новый access token. Это «договор с администрацией, что вам можно выписывать пропуска».

Смысл разделения простой: access token летает по сети в каждом запросе, значит шанс его утечь выше. Поэтому он короткий — даже если украдут, жить будет недолго. Refresh token лежит в безопасном хранилище (server-side, keychain, httpOnly cookie) и светится наружу редко.

100%
sequenceDiagram
  participant U as Пользователь
  participant C as Клиент (SPA/Mobile)
  participant AS as Authorization Server
  participant RS as Resource Server (API)

  U->>C: Открывает приложение
  C->>AS: Запрос авторизации (redirect)
  AS->>U: Форма логина + согласия
  U->>AS: Логин + пароль + "Разрешаю"
  AS->>C: Authorization code
  C->>AS: Обмен code на токены (+ client_secret)
  AS->>C: access_token + refresh_token
  C->>RS: GET /orders (Bearer access_token)
  RS->>RS: Проверка подписи JWT
  RS->>C: 200 OK, данные заказов
  Note over C,AS: Через 30 минут access_token протух
  C->>AS: POST /token (grant_type=refresh_token)
  AS->>C: Новый access_token
  C->>RS: GET /orders (Bearer новый access_token)
  RS->>C: 200 OK

На диаграмме показан полный flow Authorization Code — самый безопасный и самый распространённый сценарий OAuth 2.0. Пользователь логинится на стороне Authorization Server (клиент никогда не видит пароль), получает code, обменивает его на пару токенов и дальше общается с API по access-токену. Когда тот протухает — тихо обновляет через refresh.

Что такое JWT и при чём тут OAuth

OAuth — это протокол, он не диктует формат токена. Токен может быть хоть строкой abc123, хоть UUID, хоть чем угодно. Но на практике в 90% случаев в качестве access token используется JWT — JSON Web Token.

JWT (JSON Web Token) — это стандарт самодостаточного токена. Он состоит из трёх частей, разделённых точками: header.payload.signature. Внутри уже лежит вся нужная информация о пользователе и правах, подписанная криптографически.

Пример реального JWT (разбит на части для читаемости):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NSIsIm5hbWUiOiJQYXZlbCIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcxNDU2NzIwMH0
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Первая часть — header с алгоритмом подписи. Вторая — payload с данными (id, имя, роль, срок действия). Третья — подпись, которую сервер проверяет своим секретом.

Почему JWT так полюбили

Ключевое преимущество JWT — самодостаточность. Resource server может проверить токен локально, по одной лишь подписи, без похода в базу или в Authorization Server. Для stateless-архитектуры это подарок судьбы.

100%
graph LR
  A["Header<br/>алгоритм: HS256<br/>тип: JWT"] --> D["Токен"]
  B["Payload<br/>sub: 12345<br/>role: admin<br/>exp: 1714567200"] --> D
  C["Signature<br/>HMAC-SHA256<br/>header + payload + secret"] --> D
  D --> E["Bearer eyJhbGci...SflKxw"]

  style A fill:#4a90d9,stroke:#2c5f8a,color:#fff
  style B fill:#7b68ee,stroke:#5a4db2,color:#fff
  style C fill:#f0a500,stroke:#c88400,color:#fff
  style D fill:#50c878,stroke:#3a9a5c,color:#fff
  style E fill:#e0e0e0,stroke:#999,color:#333

Диаграмма показывает, как из трёх кирпичиков (header, payload, signature) собирается итоговый Bearer-токен. Payload виден всем — это просто base64, не шифрование. Но подделать его нельзя: изменишь хоть один байт — подпись перестанет сходиться.

Bearer: как токен попадает в запрос

Токен летает в HTTP-заголовке Authorization со схемой Bearer:

GET /api/v1/orders HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOi...
Accept: application/json

Слово Bearer дословно означает «предъявитель». Логика буквальная: кто предъявил токен — тот и пользователь. Поэтому утечка Bearer-токена равна утечке сессии. Поэтому access токены короткие. Поэтому HTTPS обязателен. Поэтому в браузерах токен лучше хранить в httpOnly cookie, а не в localStorage (где его утащит любой XSS).

OAuth Grant Types: какой flow выбрать

OAuth 2.0 описывает несколько сценариев получения токена — они называются grant types. На практике актуальны три.

Grant TypeКогда использоватьБезопасность
Authorization Code + PKCESPA, мобильные приложения, любые публичные клиентыВысокая
Client CredentialsСервис-к-сервису (M2M), без пользователяВысокая
Resource Owner PasswordТолько легаси и свои приложенияНизкая, не рекомендуется

Два других — Implicit и Device Code — либо устарели (первый), либо применяются в узких случаях (второй — для Smart TV и консолей, где ввод пароля неудобен).

PKCE — то, без чего не стоит жить в 2026

PKCE (Proof Key for Code Exchange) — это расширение Authorization Code flow, защищающее от перехвата authorization code. Клиент генерирует случайную строку (code_verifier), хэширует её и отправляет хэш при инициализации flow. Потом при обмене code на токен присылает оригинал — сервер сверяет. Злоумышленник, даже перехватив code, без verifier ничего не обменяет.

Раньше PKCE считался обязательным только для мобильных приложений. Сейчас рекомендуется для всех публичных клиентов, включая SPA.

Типичные ошибки при проектировании авторизации

За годы ревью чужих API я собрал коллекцию граблей, на которые наступает каждый третий.

  • Хранить JWT в localStorage. Любая XSS-уязвимость = утечка всех токенов. Используйте httpOnly cookie с флагами Secure и SameSite.
  • Забыть поле exp в payload. Токен становится вечным. Когда такой утечёт — будет весело (и долго).
  • Проверять токен только на Gateway. Resource server должен проверять подпись самостоятельно. Иначе любой, кто попал внутрь сети, ходит без билета.
  • Один и тот же секрет на все окружения. Dev-секрет утёк в гит → прод скомпрометирован.
  • Класть в payload всё подряд. Email, телефон, паспорт — лишнее. Payload не шифруется, он только подписан. Храните там только id и роли.
  • Не ротировать refresh token. После каждого использования refresh должен меняться. Иначе украденный refresh = бессмертная сессия.
  • Путать JWT с сессией. JWT нельзя отозвать мгновенно (он stateless). Если нужна возможность «выкинуть пользователя здесь и сейчас» — либо короткий TTL, либо блэклист, либо возвращение к серверным сессиям.

OAuth, OIDC и прочие аббревиатуры

Чтобы закрыть тему однозначно:

  • OAuth 2.0 — авторизация (делегирование доступа).
  • OpenID Connect (OIDC) — надстройка над OAuth 2.0, добавляющая аутентификацию. Именно OIDC возвращает id_token с данными пользователя (в отличие от access token, которому плевать, кто пользователь, главное — что ему можно).
  • SAML — старший брат OAuth, XML-based, живёт в корпоративном SSO (Active Directory, Okta). Если вы делаете B2C — вам не сюда.
  • API Key — не OAuth. Простой статический ключ для сервис-к-сервису без пользователя. Работает, но без гибкости и срока жизни (если только не прикрутить ротацию руками).

Хотите вход через Google в своё приложение — это OIDC поверх OAuth. Хотите защитить внутреннее API между микросервисами — Client Credentials с JWT. Хотите SSO между десятком корпоративных систем — SAML или Keycloak.

Заключение

OAuth 2.0 и JWT — это не «модная штука для стартапов», а индустриальный стандарт, без которого REST API в 2026-м проектировать уже неприлично. При этом ни OAuth, ни JWT не решают всех проблем безопасности сами по себе — это лишь кирпичи. Положите их криво — получите красивую, подписанную криптографически уязвимость.

Главное правило: токен — это секрет. Короткий срок жизни, HTTPS, ротация, httpOnly, минимальные claims в payload. Делаете это — спите спокойно. Не делаете — увидимся в новостях про очередную утечку (желательно, конечно, не в качестве главного героя).

PS: «Мы потом перепишем авторизацию» — фраза, после которой авторизация не переписывается никогда. Лучше сразу.