Prepare request uri: примеры (PYTHON)

Использование prepare_request_uri для OAuth 2.0 в Python на практике
Раздел: OAuth, Аутентификация
prepare_request_uri(uri: str, redirect_uri: str=None, scope: list=None, state: str=None, **kwargs: Any): str

Описание функции prepare_request_uri

Метод prepare_request_uri принадлежит классу oauthlib.oauth2.WebApplicationClient в библиотеке OAuthLib для Python. Он применяется для создания URI конечной точки авторизации OAuth 2.0, на который необходимо перенаправить пользовательский агент (например, браузер). Этот URI включает в себя обязательные параметры, такие как client_id, response_type, redirect_uri, а также опциональные scope, state и другие.

Метод чаще всего используется в веб-приложениях, которые следуют модели Authorization Code Grant (поток кода авторизации), но также поддерживает и другие типы ответов.

Аргументы функции

  • authorization_endpoint (str, обязательный): URL конечной точки авторизации OAuth 2.0 провайдера.
  • redirect_uri (str, необязательный): URI, на который провайдер OAuth 2.0 перенаправит пользователя после авторизации. Если не указан, используется значение, заданное при создании клиента.
  • scope (list или str, необязательный): Области доступа, которые запрашивает приложение. Могут быть переданы как список строк или как одна строка, разделенная пробелами.
  • state (str, необязательный): Случайная строка для защиты от CSRF-атак. Рекомендуется всегда использовать.
  • **kwargs: Дополнительные параметры, которые будут добавлены в строку запроса URI. Это могут быть code_challenge для PKCE, nonce для OpenID Connect и другие.

Возвращаемое значение

Функция возвращает строку (str), представляющую собой полный URI для перенаправления пользователя. Этот URI включает базовый адрес конечной точки авторизации и параметры, сформированные в виде строки запроса.

Примеры использования prepare_request_uri

Ниже представлены различные варианты вызова функции с демонстрацией результатов.

Базовый пример

Создание URI с обязательными параметрами.

from oauthlib.oauth2 import WebApplicationClient

client_id = 'ваш_идентификатор_клиента'
client = WebApplicationClient(client_id)
authorization_url = 'https://provider.com/oauth/authorize'

uri = client.prepare_request_uri(
    authorization_url,
    redirect_uri='https://yourapp.com/callback',
    scope=['read', 'write'],
    state='random_state_string'
)
print(uri)
https://provider.com/oauth/authorize?response_type=code&client_id=ваш_идентификатор_клиента&redirect_uri=https%3A%2F%2Fyourapp.com%2Fcallback&scope=read+write&state=random_state_string

Пример с параметрами PKCE

Использование расширения PKCE для публичных клиентов.

from oauthlib.oauth2 import WebApplicationClient
import hashlib
import base64
import os

client = WebApplicationClient('client_id_123')
code_verifier = base64.urlsafe_b64encode(os.urandom(40)).decode('utf-8').rstrip('=')
code_challenge = hashlib.sha256(code_verifier.encode()).digest()
code_challenge = base64.urlsafe_b64encode(code_challenge).decode('utf-8').rstrip('=')

uri = client.prepare_request_uri(
    'https://auth.server/authorize',
    redirect_uri='https://app.local/cb',
    scope='openid profile',
    state='secure_state_123',
    code_challenge=code_challenge,
    code_challenge_method='S256'
)
print(uri[:120] + '...')
https://auth.server/authorize?response_type=code&client_id=client_id_123&redirect_uri=https%3A%2F%2Fapp.local%2Fcb&scope=openid+profile&state=secure_state_123&code_challenge=...&code_challenge_method=S256

Похожие функции в Python

Библиотека OAuthLib предоставляет другие клиенты и методы для работы с OAuth 2.0.

  • WebApplicationClient.prepare_authorization_request: Аналогичный метод, который возвращает кортеж из URI, заголовков и тела запроса. Может быть полезен для нестандартных HTTP-запросов.
  • MobileApplicationClient.prepare_request_uri: Клиент для мобильных приложений (Implicit Grant). Использует response_type='token' по умолчанию.
  • LegacyApplicationClient: Клиент для доверенных приложений (Resource Owner Password Credentials Grant). Не использует prepare_request_uri, так как авторизация происходит без перенаправления пользователя.
  • BackendApplicationClient: Клиент для сервер-серверного взаимодействия (Client Credentials Grant).

Метод prepare_request_uri WebApplicationClient является основным для классического веб-потока с кодом авторизации.

Типичные ошибки при использовании

Неверный или отсутствующий URI перенаправления

Если redirect_uri не передан в метод и не был установлен при создании клиента, возникнет ошибка.

client = WebApplicationClient('client_id')
try:
    uri = client.prepare_request_uri('https://provider.com/auth')
except ValueError as e:
    print(f'Ошибка: {e}')
Ошибка: Missing redirect_uri.

Некорректная кодировка параметров

Функция автоматически кодирует параметры. Попытка передать уже закодированную строку может привести к двойному кодированию.

# Неправильно: ручное кодирование
uri = client.prepare_request_uri(
    'https://provider.com/auth',
    redirect_uri='https%3A%2F%2Fapp.com%2Fcb',  # Уже закодировано
    state='test'
)
print(uri)  # redirect_uri будет закодирован повторно
https://provider.com/auth?response_type=code&client_id=client_id&redirect_uri=https%253A%252F%252Fapp.com%252Fcb&state=test

В результате провайдер может не распознать URI.

Использование небезопасного состояния (state)

Отсутствие параметра state или использование предсказуемого значения делает приложение уязвимым к CSRF-атакам.

История изменений функции

Метод prepare_request_uri долгое время оставался стабильным. Основные изменения в библиотеке OAuthLib касались улучшения безопасности и поддержки новых расширений спецификации OAuth 2.0.

  • Версия 3.x: Улучшена поддержка PKCE (RFC 7636). Параметры code_challenge и code_challenge_method стали корректно обрабатываться как часть **kwargs.
  • Более ранние версии: В версиях до 2.0.0 могли отличаться названия некоторых параметров или детали обработки scope. Рекомендуется использовать версии 3.x и выше.

При обновлении библиотеки стоит обратить внимание на объявление нерекомендуемых (deprecated) способов вызова, хотя сигнатура данного метода не претерпела кардинальных изменений.

Расширенные примеры использования

Интеграция с конкретным провайдером (GitHub)

Пример формирования URI для GitHub OAuth App с использованием пользовательских параметров.

Пример python
from oauthlib.oauth2 import WebApplicationClient

client = WebApplicationClient(client_id='github_client_id')
github_auth_url = 'https://github.com/login/oauth/authorize'

uri = client.prepare_request_uri(
    github_auth_url,
    redirect_uri='http://localhost:8000/auth/callback',
    scope=['user', 'repo'],
    state='unique_session_state_xyz',
    allow_signup='false'  # Специфичный параметр GitHub
)
print(uri)
https://github.com/login/oauth/authorize?response_type=code&client_id=github_client_id&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fauth%2Fcallback&scope=user+repo&state=unique_session_state_xyz&allow_signup=false

Использование нестандартного response_type

Некоторые провайдеры поддерживают гибридные потоки OpenID Connect.

Пример python
from oauthlib.oauth2 import WebApplicationClient

client = WebApplicationClient(client_id='oidc_client', default_response_type='code id_token')

uri = client.prepare_request_uri(
    'https://oidc.provider.com/authorize',
    redirect_uri='https://app.com/callback',
    scope='openid email',
    state='state_123',
    nonce='nonce_456',  # Обязательный параметр для OpenID Connect
    response_mode='fragment'  # Указание режима ответа
)
print(uri[:150] + '...')
https://oidc.provider.com/authorize?response_type=code+id_token&client_id=oidc_client&redirect_uri=https%3A%2F%2Fapp.com%2Fcallback&scope=openid+email&state=state_123&nonce=nonce_456&response_mode=fragment...

Динамическое изменение scope на основе действий пользователя

Создание разных URI для запроса разных наборов разрешений в рамках одного приложения.

Пример python
def generate_auth_url(base_scopes, extra_scopes=None):
    client = WebApplicationClient('dynamic_client')
    all_scopes = base_scopes
    if extra_scopes:
        all_scopes.extend(extra_scopes)
    uri = client.prepare_request_uri(
        'https://api.service.com/oauth2/auth',
        redirect_uri='https://app.com/cb',
        scope=all_scopes,
        state='dynamic_scope_state'
    )
    return uri

# Запрос базовых прав
url1 = generate_auth_url(['profile'])
print('URL1:', url1.split('scope=')[1].split('&')[0])
# Запрос базовых прав + дополнительных
url2 = generate_auth_url(['profile'], ['email', 'messages:read'])
print('URL2:', url2.split('scope=')[1].split('&')[0])
URL1: profile
URL2: profile+email+messages%3Aread

Альтернативы в других языках программирования

В других экосистемах существуют схожие библиотеки для построения URI авторизации OAuth 2.0.

JavaScript (Node.js)

Библиотека openid-client или simple-oauth2. Обычно используется метод, конфигурирующий клиент, который затем генерирует URL.

const { Issuer } = require('openid-client');
(async () => {
  const googleIssuer = await Issuer.discover('https://accounts.google.com');
  const client = new googleIssuer.Client({
    client_id: 'CLIENT_ID',
    redirect_uris: ['https://yourapp.com/callback']
  });
  const authorizationUrl = client.authorizationUrl({
    scope: 'openid email',
    state: 'some_state'
  });
  console.log(authorizationUrl);
})();

PHP

Библиотека league/oauth2-client предоставляет класс AbstractProvider с методом getAuthorizationUrl().

$provider = new \League\OAuth2\Client\Provider\GenericProvider([
    'clientId' => 'CLIENT_ID',
    'redirectUri' => 'https://yourapp.com/callback',
    'urlAuthorize' => 'https://provider.com/oauth/authorize'
]);
$authorizationUrl = $provider->getAuthorizationUrl(['scope' => 'read']);
$_SESSION['oauth2state'] = $provider->getState();
echo $authorizationUrl;

Java

Фреймворк Spring Security OAuth 2.0 Client использует класс AuthorizationCodeGrantRequest для конструирования URI через OAuth2AuthorizationRequestResolver.

// Конфигурация через свойства приложения. Генерация URI происходит автоматически фреймворком.
// Прямого аналога в одну строку нет, процесс инкапсулирован.

Ключевое отличие Python-реализации в использовании универсального клиента WebApplicationClient, которому не требуется предварительная регистрация специфичных для провайдера настроек, что обеспечивает гибкость, но может требовать больше ручной работы.

питон prepare_request_uri function comments

En
Prepare request uri Prepare the request URI