Авторизация по протоколу OAuth 2.0 в интеграциях

от автора

В интеграциях с внешними приложениями часто используется протокол OAuth 2.0. Он позволяет приложению получить доступ к данным пользователя без передачи пароля. В этой статье разбирается практический сценарий: получение access_token, обновление токена, работа с ошибками и использование токена аккаунта для фоновых операций.

Подробная диаграмма последовательности процесса авторизации.

Диаграмма процесса авторизации по OAuth 2.0

Диаграмма процесса авторизации по OAuth 2.0

Далее описан алгоритм авторизации по протоколу OAuth 2.0.

1 Инициация — получение параметров аккаунта

Пользователь переходит из страницы настройки интеграции в стороннее приложение. В URL передаются параметры аккаунта: account_id и account_name

https://%domain%.ru/api/oauth2/auth?account\_id=<идентификатор аккаунта>&account_name=<наименование аккаунта>

Стороннее приложение сохраняет account_id (идентификатор аккаунта) и account_name(наименование аккаунта). Они потребуются при создании подключения и получении токена аккаунта.

2 Перенаправление на сервер аутентификации

Приложение перенаправляет пользователя на сервер аутентификации для получения кода авторизации — authorization code :

https://id.provider.com/authorize

Параметры запроса:

Параметр

Описание

client_id

Идентификатор стороннего приложения

redirect_uri

URL, на который сервер авторизации перенаправляет пользователя после успешной авторизации.

scope

Запрашиваемые права стороннего приложения

state

Защита от подделки

https://id.provider.com/authorize?client_id=1xx1x111-1x11-1111-1xx1-x1xx1xx1xx1x&redirect_uri=http://example.com/callback&scope=<права стороннего приложения>&state=123

После успешного входа сервер возвращает временный код авторизации, который может быть использован только один раз — authorization code. Время жизни кода ограничено.

3 Получение access_token и refresh_token (обмен кода на токены)

Сервер стороннего приложения выполняет POST-запрос к серверу аутентификации:

curl -X POST https://id.provider.com/token \  -H "Authorization: Basic base64(client_id:client_secret)" \  -H "Content-Type: application/x-www-form-urlencoded" \  -d "code=AUTHORIZATION_CODE" \  -d "grant_type=authorization_code" \  -d "redirect_uri=https://your-app.com/callback"

Параметры запроса:

Параметр

Описание

code

Временный код, полученный на предыдущем шаге

grant_type

authorization_code

redirect_uri

URL возврата (должен совпадать с указанным ранее)

В ответе приходит json с access_token и refresh_token. Формат успешного ответа, если access_token получен:

{  "token_type": "Bearer",  "user_id": "1111111ч-11x-1111-xx11-x1x111x11111",  "expires_in": 3600,  "expires_at": "2026-01-01T10:10:10+03:00",  "access_token": "<accesstoken>",  "refresh_token": "<refreshtoken>",  "refresh_expires_in": 2500000,  "refresh_expires_at": "2028-01-01T12:04:54+03:00"}

Параметры ответа:

Параметр

Описание

token_type

Всегда Bearer

user_id

Уникальный идентификатор пользователя

expires_in

Время жизни access_token в секундах

expires_at

Дата и время истечения access_token

access_token

Токен доступа (короткоживущий, обычно 1 час)

refresh_token

Токен для обновления access_token (долгоживущий)

refresh_expires_in

Время жизни refresh_token в секундах

refresh_expires_at

Дата и время истечения refresh_token

Формат ответа при ошибке

{  "error": "invalid_grant",  "error_description": "Code is expired."}

После получения access_token приложение создаёт подключение в ресурсном сервере:

curl -X POST https://account.provider.com/api/rest/create.json \  -H "Authorization: Bearer <access_token>" \  -H "Content-Type: application/json" \  -d '{}'

В случае успешного запроса, в ответе вернется app_id — идентификатор подключения.

4 Как обновить access_token

Срок жизни access_token ограничен. После истечения срока жизни токена пользователю необходимо вновь пройти авторизацию. Чтобы не проходить авторизацию заново, когда access_token истекает, его обновляют через refresh_token. refresh_token всегда выдается с access_token в одном ответе.

curl -X POST https://id.provider.com/token \  -H "Content-Type: application/x-www-form-urlencoded" \  -d "grant_type=refresh_token" \  -d "refresh_token=<указать полученный ранее refresh_token>" \  -d "client_id=<Идентификатор стороннего приложения  >" 

В результате токен обновится или появится информация об ошибке.

После получения access_token приложение создаёт подключение в ресурсном сервере с помощью запроса:

curl -X POST https://account.provider.com/api/rest/create.json \  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \  -H "Content-Type: application/json" \  -d '{}'

В случае успешного запроса, в ответе вернется app_id — идентификатор подключения.

5 Токен аккаунта для фоновых процессов

После получения пользовательского access_token и refresh_token возникает вопрос: что делать, если интеграции нужно работать в фоне — без участия пользователя? В таких случаях используется токен аккаунта (account_token).

Без токена аккаунта фоновые операции привязаны к конкретному пользователю. Если пользователь выйдет из системы или его сессия истечёт — интеграция перестанет работать. Токен аккаунта привязан не к пользователю, а к аккаунту, и может работать независимо.

Пример запроса на получение access_token аккаунта

curl -X POST https://id.provider.com/token \  -H "Authorization: Basic base64(client_id:client_secret)" \  -H "Content-Type: application/x-www-form-urlencoded" \  -d "grant_type=account_token" \  -d "access_token=USER_ACCESS_TOKEN" \  -d "account_client_id=111x1111-x111-x111-xx1x-111x11x111xx" \  -d "account_id=111"

Что важно учесть

  1. Для фоновых операций используй токен аккаунта — он не привязан к сессии пользователя и подходит для автоматических сценариев.

  2. access_token имеет ограниченный срок жизни — следует обновлять его заранее через refresh_token, чтобы избежать сбоев в работе интеграции

  3. Не выводить токены в логи

  4. Заложить права доступа не только на сервере, но и в приложении, чтобы корректно обрабатывать ошибки

ссылка на оригинал статьи https://habr.com/ru/articles/1054840/