← Назад к вопросам
В чём разница между scope в OpenID и OAuth2?
1.7 Middle🔥 181 комментариев
#REST API и HTTP#Безопасность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Scope в OpenID Connect vs OAuth2: фундаментальные различия
Это очень важный вопрос, потому что многие разработчики путают OAuth2 и OpenID Connect, думая что это одно и то же. На самом деле это разные протоколы, и scope в них используется по-разному.
Первое: что это вообще
OAuth2 — это протокол АВТОРИЗАЦИИ
OAuth2 отвечает на вопрос:
"Какие ресурсы приложение может получить от пользователя?"
OpenID Connect — это слой АУТЕНТИФИКАЦИИ поверх OAuth2
OpenID Connect отвечает на вопрос:
"Кто это пользователь и какая у него информация?"
┌──────────────────────────────┐
│ OpenID Connect (Auth) │ ← Узнаём КОГО мы авторизуем
├──────────────────────────────┤
│ OAuth2 (Authz) │ ← Что разрешено делать
└──────────────────────────────┘
Scope в OAuth2
Что это
Scope в OAuth2 — это разрешения (permissions) для доступа к ресурсам. Это уровень АВТОРИЗАЦИИ.
Пользователь:
"Приложение просит доступ к моим:
- профилю
- календарю
- контактам
ОК или отклонить?"
Примеры scope'ов OAuth2
# Google OAuth2 scopes
scopes = [
'https://www.googleapis.com/auth/userinfo.profile', # Профиль
'https://www.googleapis.com/auth/userinfo.email', # Email
'https://www.googleapis.com/auth/calendar', # Календарь
'https://www.googleapis.com/auth/drive', # Google Drive
]
# GitHub OAuth2 scopes
scopes = [
'repo', # Полный доступ к репозиториям
'read:user', # Читать профиль
'user:email', # Читать email'ы
'workflow', # Действия с workflow
]
Как это работает (OAuth2 поток)
1. Приложение запрашивает authorization
https://provider.com/oauth/authorize?scope=profile,email
2. Пользователь видит:
"Приложение 'MyApp' запрашивает:
- Доступ к профилю
- Доступ к email
[Разрешить] [Отклонить]"
3. Если разрешить, приложение получает access_token
4. С этим token'ом приложение может получить ресурсы
GET /api/user/profile
Authorization: Bearer <access_token>
Ответ: {
"name": "Alice",
"email": "alice@example.com"
}
Пример: OAuth2 с Python
from authlib.integrations.flask_client import OAuth
oauth = OAuth()
google = oauth.register(
name='google',
client_id='...',
client_secret='...',
server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
client_kwargs={
'scope': 'openid profile email' # OAuth2 scope'ы
}
)
@app.route('/login')
def login():
redirect_uri = url_for('authorize', _external=True)
return google.authorize_redirect(redirect_uri)
@app.route('/authorize')
def authorize():
token = google.authorize_access_token()
user_info = token.get('userinfo') # Информация о пользователе
return jsonify(user_info)
Scope в OpenID Connect
Что это
Scope в OpenID Connect — это какую информацию о пользователе мы хотим получить в ID token'е.
Это НЕ о доступе к ресурсам.
Это о том, какую ИНФОРМАЦИЮ О ПОЛЬЗОВАТЕЛЕ
получить в ID token'е.
Стандартные OpenID Connect scope'ы
# OpenID Connect scope'ы (стандартные)
scopes = [
'openid', # ОБЯЗАТЕЛЕН! Включает ID token
'profile', # name, family_name, given_name, picture, birthdate, etc.
'email', # email, email_verified
'address', # street_address, locality, postal_code, etc.
'phone', # phone_number, phone_number_verified
]
# Это NOT разрешения на действия!
# Это просто "включить эту информацию в ID token"
Содержимое ID Token (с разными scope'ами)
# Без scope (openid только)
{
"iss": "https://provider.com",
"sub": "user123", # Subject ID (всегда)
"aud": "client_id",
"exp": 1234567890,
"iat": 1234567800
}
# С scope: openid profile
{
"iss": "https://provider.com",
"sub": "user123",
"aud": "client_id",
"name": "Alice",
"family_name": "Smith",
"given_name": "Alice",
"picture": "https://example.com/alice.jpg",
"locale": "en-US"
}
# С scope: openid email
{
"iss": "https://provider.com",
"sub": "user123",
"aud": "client_id",
"email": "alice@example.com",
"email_verified": true
}
# С scope: openid profile email
{
"iss": "https://provider.com",
"sub": "user123",
"aud": "client_id",
"name": "Alice",
"email": "alice@example.com",
"email_verified": true,
"picture": "https://example.com/alice.jpg"
}
Пример: OpenID Connect с Python
from authlib.integrations.flask_client import OAuth
from authlib.jose import jwt
oauth = OAuth()
Google = oauth.register(
name='google',
client_id='...',
client_secret='...',
server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
client_kwargs={
'scope': 'openid profile email' # OpenID Connect scope'ы
}
)
@app.route('/login')
def login():
redirect_uri = url_for('authorize', _external=True)
return Google.authorize_redirect(redirect_uri)
@app.route('/authorize')
def authorize():
token = Google.authorize_access_token()
# ID token содержит информацию о пользователе
id_token = token.get('id_token')
user_info = jwt.decode(id_token, options={'verify_signature': False})
print(user_info) # {
# "iss": "https://accounts.google.com",
# "sub": "110169547...",
# "name": "Alice",
# "email": "alice@example.com",
# "picture": "https://...",
# "email_verified": true
# }
# Создаём сессию пользователя
session['user'] = user_info
return redirect('/')
Сравнение OAuth2 vs OpenID Connect
| Аспект | OAuth2 | OpenID Connect |
|---|---|---|
| Назначение | АВТОРИЗАЦИЯ | АУТЕНТИФИКАЦИЯ |
| Отвечает на | "Что может делать?" | "Кто это?" |
| Возвращает | access_token | ID token + access_token |
| scope | Разрешения на ресурсы | Информация в ID token'е |
| Типичный scope | repo, calendar, drive | openid, profile, email |
| Нужна ли программа? | Да (чтобы что-то делать) | Нет (просто узнать кто) |
| ID token | Нет (не обязателен) | Да (обязателен) |
Реальная жизнь: пример с Google
OAuth2: доступ к Google Drive
Получаем доступ к файлам пользователя в Google Drive
scope: 'https://www.googleapis.com/auth/drive'
↓
access_token
↓
GET https://www.googleapis.com/drive/v3/files
Authorization: Bearer <access_token>
↓
[
{ id: "file1", name: "Document.docx" },
{ id: "file2", name: "Spreadsheet.xlsx" }
]
OpenID Connect: авторизация на сайте
Пользователь нажимает "Sign in with Google"
scope: 'openid profile email'
↓
ID token (содержит информацию)
↓
ID token декодирован:
{
"sub": "110169547...",
"name": "Alice",
"email": "alice@example.com",
"email_verified": true
}
↓
Заходим в приложение как alice@example.com
Пример: полный OpenID Connect поток
from flask import Flask, url_for, session, redirect
from authlib.integrations.flask_client import OAuth
from authlib.jose import jwt
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
oauth = OAuth(app)
# Регистрируем Google как OpenID Provider
google = oauth.register(
name='google',
client_id='YOUR_CLIENT_ID',
client_secret='YOUR_CLIENT_SECRET',
server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
client_kwargs={
'scope': 'openid profile email' # OpenID Connect scope'ы
}
)
@app.route('/')
def index():
return '''<a href="/login">Sign in with Google</a>'''
@app.route('/login')
def login():
redirect_uri = url_for('authorize', _external=True)
return google.authorize_redirect(redirect_uri)
@app.route('/authorize')
def authorize():
token = google.authorize_access_token()
# Декодируем ID token (без проверки подписи для примера)
id_token_str = token['id_token']
user_info = jwt.decode(id_token_str, options={'verify_signature': False})
# Сохраняем в сессию
session['user'] = {
'id': user_info['sub'],
'name': user_info.get('name'),
'email': user_info.get('email'),
'picture': user_info.get('picture')
}
return redirect('/dashboard')
@app.route('/dashboard')
def dashboard():
user = session.get('user')
if not user:
return redirect('/login')
return f'''<html>
<body>
<h1>Welcome, {user['name']}!</h1>
<p>Email: {user['email']}</p>
<img src="{user['picture']}">
<a href="/logout">Logout</a>
</body>
</html>'''
@app.route('/logout')
def logout():
session.pop('user', None)
return redirect('/')
if __name__ == '__main__':
app.run()
Ошибки: что часто путают
❌ Ошибка 1: OAuth2 scope вместо OpenID
# НЕПРАВИЛЬНО (OAuth2, не OpenID)
scope='repo,user:email' # GitHub scope'ы
# ПРАВИЛЬНО (OpenID Connect)
scope='openid profile email'
❌ Ошибка 2: смешивание OAuth2 и OpenID
# НЕПРАВИЛЬНО (микс)
scope='openid profile email drive' # Смешиваем OpenID и OAuth2
# ПРАВИЛЬНО (оба есть, но разные)
scope='openid profile email' # OpenID
scope='https://www.googleapis.com/auth/drive' # OAuth2
❌ Ошибка 3: использование userinfo endpoint вместо ID token
# НЕПРАВИЛЬНО (лишний запрос)
user_info = requests.get(
'https://accounts.google.com/oauth/userinfo',
headers={'Authorization': f'Bearer {access_token}'}
).json()
# ПРАВИЛЬНО (уже есть в ID token)
user_info = jwt.decode(id_token, options={'verify_signature': False})
Когда какой использовать
OAuth2 нужен когда:
- Приложение должно "делать что-то" от имени пользователя
- Получить доступ к файлам, календарю, почте
- Опубликовать пост в соцсети
- Изменить чужие ресурсы
OpenID Connect нужен когда:
- Просто узнать кто пользователь
- Авторизация на сайте
- Заполнить профиль после регистрации
- SSO (Single Sign-On)
Заключение
Scope в OAuth2 — это разрешения для доступа к API. Scope в OpenID Connect — это информация в ID token'е.
Слово "scope" одно, но использование принципиально разное.
Психологический лайфхак:
- OAuth2 scope → "Могу ли я...?" (делать что-то)
- OpenID scope → "Знаю ли я...?" (информацию о пользователе)