Налаштування Google OAuth 2.0 у Flask (PythonAnywhere)
Цей допис — покрокова інструкція для себе, щоб наступного разу налаштування авторизації через Google у Flask не забрало півдня і не викликало MismatchingStateError.
📦 Залежності
flask
authlib
python-dotenv
flask-login
(опційно)werkzeug.middleware.proxy_fix.ProxyFix
1. Створити файл .env
GOOGLE_CLIENT_ID=тут_твій_id
GOOGLE_CLIENT_SECRET=тут_секрет
SECRET_KEY=фіксований_ключ
2. Налаштування flask_app.py
from flask import Flask
from werkzeug.middleware.proxy_fix import ProxyFix
from dotenv import load_dotenv
import os
from pathlib import Path
project_root = Path(__file__).resolve().parent
load_dotenv(dotenv_path=project_root / '.env')
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)
app.config.update(
SECRET_KEY=os.getenv("SECRET_KEY"),
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_SAMESITE="None",
PREFERRED_URL_SCHEME="https",
GOOGLE_CLIENT_ID=os.getenv("GOOGLE_CLIENT_ID"),
GOOGLE_CLIENT_SECRET=os.getenv("GOOGLE_CLIENT_SECRET"),
)
from auth import auth_bp, oauth, login_manager, init_oauth
init_oauth(app)
app.register_blueprint(auth_bp)
oauth.init_app(app)
login_manager.init_app(app)
3. Налаштування auth.py
from flask import Blueprint
from authlib.integrations.flask_client import OAuth
from flask_login import LoginManager
auth_bp = Blueprint('auth', __name__)
oauth = OAuth()
login_manager = LoginManager()
google = None
def init_oauth(app):
global google
google = oauth.register(
name='google',
client_id=app.config.get("GOOGLE_CLIENT_ID"),
client_secret=app.config.get("GOOGLE_CLIENT_SECRET"),
access_token_url='https://oauth2.googleapis.com/token',
authorize_url='https://accounts.google.com/o/oauth2/auth',
client_kwargs={
'scope': 'openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile'
}
)
4. Роути /login
та /auth/callback
@auth_bp.route('/login')
def login():
redirect_uri = url_for('auth_callback', _external=True, _scheme="https")
print(f"[DEBUG] session before redirect: {dict(session)}")
return google.authorize_redirect(redirect_uri)
@auth_bp.route('/auth/callback')
def auth_callback():
print(f"[DEBUG] session on callback: {dict(session)}")
try:
token = google.authorize_access_token()
userinfo = google.parse_id_token(token)
print("[DEBUG] userinfo:", userinfo)
return redirect(url_for("review"))
except Exception as e:
print("[ERROR]", e)
return "OAuth error"
❌ Типові помилки і як їх уникнути
Помилка | Причина | Рішення |
---|---|---|
MismatchingStateError | Кука не зберігається або не повертається | Додати ProxyFix, SESSION_COOKIE_SAMESITE="None", SECURE=True |
client_id=None | client_id зчитується до load_dotenv() | Зберігати client_id у app.config, а не через os.getenv під час імпорту |
RuntimeError: working outside of application context | current_app використовується під час імпорту | Викликати oauth.register у функції init_oauth(app) |
Cookie зникає після редиректу | SESSION_COOKIE_SAMESITE неправильний | Поставити SESSION_COOKIE_SAMESITE="None", SECURE=True |
🧪 Як перевірити
- У браузері відкрий DevTools (F12) → Application → Cookies → leox.pythonanywhere.com
- Перевір, чи є
session
-cookie - У вкладці Network → auth/callback → заголовки запиту → перевір, чи передалась кука
✅ Тестування
print("[DEBUG] session:", dict(session))
print("[DEBUG] redirect_uri:", redirect_uri)
Якщо після логіну все працює — побачите токен, і Flask сесія залишиться живою після редиректу.
---🧠 Урок: у Flask найважливіше — порядок ініціалізації, контекст і cookie. Якщо ці три речі під контролем — навіть Google OAuth здається логічним.
Немає коментарів:
Дописати коментар