← назад к разделу

Представьте: вы хотите, чтобы стороннее приложение (например, сервис подбора фотографий) залезло в ваш фотоальбом в облаке. Отдавать ему ваш логин и пароль от облака — плохая идея: он получит полный доступ ко всему, и пароль придётся менять у всех сразу, если он утечёт. Нужен способ выдать ограниченный, отзываемый доступ без передачи пароля. Именно эту задачу решает OAuth2, а OIDC добавляет к ней ответ на вопрос «а кто, собственно, этот пользователь».

Зачем вообще OAuth2: проблема «отдать пароль»

Старый способ — дать приложению свой пароль — ломается сразу по нескольким причинам:

  • приложение видит ваш пароль (а значит, может всё);
  • доступ нельзя ограничить — «только чтение фотографий» не выразить;
  • отозвать доступ у одного приложения нельзя, не меняя пароль везде.

OAuth2 — это протокол делегирования доступа. Вы разрешаете приложению действовать от вашего имени в строго оговорённых рамках, не показывая ему пароль. Вместо пароля приложение получает токен — временный «пропуск» с ограниченными правами, который в любой момент можно отозвать.

Ключевая мысль: OAuth2 — про доступ (что приложению разрешено делать), а не про вашу личность.

Четыре роли OAuth2 на аналогии с отелем

В OAuth2 всегда четыре участника. Разберём их на аналогии: вы заселяетесь в отель.

  • Владелец ресурса (resource owner) — это вы, гость. Ресурс — ваш номер; именно вы решаете, кто туда войдёт.
  • Сервер авторизации (authorization server)стойка регистрации. Вы показываете паспорт, и вам выдают ключ-карту. Стойка проверяет, кто вы, и решает, что вам можно.
  • Клиент (client) — приложение, которому нужен доступ. В аналогии это уборщик или служба доставки еды, которому вы разрешили заходить в номер. Он не владелец, он действует с вашего разрешения.
  • Сервер ресурсов (resource server)дверной замок номера. Он не знает вас лично, он просто проверяет: подходит ключ-карта — пускает, не подходит — нет.

Связка простая: владелец ресурса (вы) разрешает на сервере авторизации (стойке) выдать клиенту (уборщику) ключ-карту (токен), а сервер ресурсов (замок) пускает по этой карте.

В терминах реальной системы: стоит сервер авторизации (например, Keycloak), есть ваше приложение (клиент), есть API с данными (сервер ресурсов), и есть вы (владелец ресурса).

Access token: пропуск для доступа к API

Проблема: API должно как-то понять, что входящий запрос разрешён, не спрашивая каждый раз пароль.

Access token (токен доступа) — это и есть ключ-карта. Клиент прикладывает его к каждому запросу к API, обычно в заголовке:

GET /albums/42/photos
Authorization: Bearer eyJhbGciOiJSUzI1Niis...

Свойства access token, которые важно понимать:

  • короткоживущий — обычно минуты (часто 5–15). Если утечёт, ущерб ограничен по времени.
  • несёт scope (об этом ниже) — какие именно действия разрешены.
  • сервер ресурсов проверяет его сам, не дёргая каждый раз сервер авторизации (если токен — подписанный JWT, проверяется подпись).

Access token адресован серверу ресурсов (API). Это «пропуск делать», а не «удостоверение личности».

Refresh token: чтобы не логиниться каждые 10 минут

Проблема: если access token живёт 10 минут, пользователю пришлось бы заново вводить логин и пароль каждые 10 минут. Это невыносимо.

Refresh token (токен обновления) решает это. Он живёт долго (часы, дни, иногда дольше) и хранится в безопасном месте на стороне клиента. Когда access token истекает, клиент молча обменивает refresh token на новый access token — без участия пользователя.

POST /token
grant_type=refresh_token
refresh_token=<длинный-токен>

Зачем такое разделение «короткий + длинный»:

  • access token часто гуляет по сети (в каждом запросе к API) — поэтому он короткий, чтобы кража быстро обесценилась;
  • refresh token почти не двигается (только при обновлении) и хранится бережнее — поэтому может жить долго;
  • refresh token можно отозвать на сервере авторизации, и тогда клиент больше не сможет обновлять доступ.

Refresh token адресован серверу авторизации — только он умеет его принять и выдать новый access token.

ID token и OIDC: ответ на вопрос «кто ты»

Тут важная развилка. OAuth2 сам по себе ничего не говорит о личности пользователя. Access token отвечает на вопрос «что можно делать», но не на вопрос «кто это». Если приложение хочет показать «Здравствуйте, Анна» — из чистого OAuth2 это надёжно не вытащить (access token формально вообще непрозрачен для клиента).

OIDC (OpenID Connect) — это тонкая надстройка над OAuth2, которая добавляет аутентификацию: способ узнать и доказать, кто пользователь. Делает она это через третий тип токена.

ID token — это всегда JWT (подписанный JSON), который описывает пользователя. Внутри — набор полей (claims):

{
  "iss": "https://keycloak.example.com/realms/myrealm",
  "sub": "a1b2c3d4-...",
  "aud": "my-web-app",
  "exp": 1735690000,
  "iat": 1735689700,
  "name": "Анна Иванова",
  "email": "anna@example.com"
}

Что значат ключевые поля:

  • iss (issuer) — кто выдал токен (адрес сервера авторизации).
  • sub (subject) — стабильный уникальный идентификатор пользователя. Именно он, а не email, — настоящий «ключ» пользователя.
  • aud (audience) — для какого приложения токен предназначен. Чужой aud принимать нельзя.
  • exp / iat — когда истекает / когда выдан.

Главное правило, которое легко перепутать: ID token предназначен клиенту (приложению — чтобы узнать пользователя), access token — серверу ресурсов (API — чтобы решить, пускать ли). Не используйте ID token для доступа к API и не пытайтесь читать содержимое access token как профиль пользователя.

OAuth2 против OIDC: одной фразой

Их постоянно путают, поэтому зафиксируем разницу:

  • OAuth2 — про авторизацию (доступ). «Этому приложению разрешено читать мои фотографии.» Инструмент — access token.
  • OIDC — про аутентификацию (личность). «Этот пользователь — Анна, и это подтверждено сервером авторизации.» Инструмент — ID token.

OIDC не заменяет OAuth2, а достраивается поверх него: тот же поток получения токенов, но в ответ добавляется ID token и стандартные поля о пользователе. Когда вы видите кнопку «Войти через ...» — за ней почти всегда OIDC, а не голый OAuth2.

Scopes: ограничение «что именно можно»

Проблема: «дать доступ» — слишком грубо. Сервису подбора фотографий нужно только читать альбомы, а не удалять их и не лезть в платёжные данные.

Scope — это запрашиваемый объём прав, выраженный короткими метками. Клиент при входе говорит, что ему нужно, а пользователь это подтверждает (часто — на экране согласия):

scope=openid profile email albums:read

Здесь:

  • openid — особый scope: его наличие включает OIDC, то есть «выдай ещё и ID token». Без openid это просто OAuth2 без сведений о личности.
  • profile, email — стандартные OIDC-наборы полей: имя, email и т.п. в ID token.
  • albums:read — пример прикладного права для вашего API.

Полученный access token несёт согласованные scope, и сервер ресурсов по ним решает, что разрешить. Принцип — минимально необходимый доступ: просите только те scope, которые реально нужны.

Как это собирается вместе: Authorization Code Flow в двух словах

Самый распространённый способ получить токены для веб- и мобильных приложений называется Authorization Code Flow. В упрощённом виде:

  1. Приложение (клиент) отправляет пользователя на сервер авторизации на страницу входа.
  2. Пользователь вводит логин и пароль там же, на сервере авторизации — приложение их не видит.
  3. Сервер авторизации возвращает приложению одноразовый код авторизации (authorization code).
  4. Приложение на своём бэкенде обменивает этот код на токены: access token, refresh token и (если был scope openid) ID token.

Важная деталь: пароль вводится только на сервере авторизации, а приложение получает не пароль, а короткоживущий код, который тут же меняет на токены. Для публичных клиентов (мобильные приложения, SPA) шаг обмена защищают механизмом PKCE, чтобы перехваченный код нельзя было использовать.

Это лишь общая картина — детали (зачем нужен код, как именно работает PKCE, как устроен экран согласия) разбираются в отдельной статье про Authorization Code Flow.

Коротко

  • OAuth2 даёт приложению ограниченный отзываемый доступ без передачи пароля — это про доступ (авторизацию делегирования).
  • Четыре роли: владелец ресурса (пользователь), клиент (приложение), сервер авторизации (выдаёт токены), сервер ресурсов (API, проверяет токены).
  • Access token — короткоживущий пропуск к API, адресован серверу ресурсов.
  • Refresh token — долгоживущий, обменивается на новый access token без участия пользователя, адресован серверу авторизации.
  • ID token — всегда JWT о личности пользователя, адресован клиенту; появляется только с OIDC и scope openid.
  • OIDC — надстройка над OAuth2 про аутентификацию («кто ты»); OAuth2 — про авторизацию («что можно»).
  • Scopes ограничивают объём прав; openid включает OIDC, profile/email добавляют поля о пользователе.
  • Authorization Code Flow — основной способ получить токены: пароль вводится на сервере авторизации, приложение получает код и меняет его на токены.

Что почитать дальше

  • Authorization Code Flow подробно — зачем нужен код, шаги потока и PKCE.
  • JWT validation в Spring Security — как сервер ресурсов проверяет токен через oauth2ResourceServer и JWK Set.
  • RBAC: маппинг ролей JWT и @PreAuthorize — как роли из токена превращаются в права на эндпоинтах.