|
1 | | -from flask import (Blueprint, render_template, redirect, url_for, session, |
2 | | - request, jsonify, current_app) |
| 1 | +from flask import ( |
| 2 | + Blueprint, |
| 3 | + render_template, |
| 4 | + redirect, |
| 5 | + url_for, |
| 6 | + session, |
| 7 | + current_app, |
| 8 | + g, |
| 9 | +) |
3 | 10 | from authlib.integrations.flask_client import OAuth |
4 | 11 | from dotenv import load_dotenv |
5 | 12 | import os |
| 13 | +from functools import wraps |
| 14 | + |
6 | 15 |
|
7 | 16 | # Allow HTTP for local development (required for OAuth2Session) |
8 | | -os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' |
| 17 | +os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1" |
9 | 18 |
|
10 | 19 | load_dotenv() |
11 | 20 |
|
12 | | -# Get redirect URI for OAuth callbacks |
13 | | -redirect_uri = 'http://127.0.0.1:5000/api/auth/callbacks/gamma' |
14 | 21 |
|
15 | | -auth = Blueprint('auth', __name__) |
| 22 | +auth = Blueprint("auth", __name__) |
| 23 | + |
| 24 | + |
| 25 | +def get_gamma(): |
| 26 | + oauth: OAuth = current_app.extensions["authlib.integrations.flask_client"] |
| 27 | + return oauth.gamma |
| 28 | + |
16 | 29 |
|
| 30 | +def login_required(f): |
| 31 | + @wraps(f) |
| 32 | + def decorated_function(*args, **kwargs): |
| 33 | + if not session.get("authenticated"): |
| 34 | + return redirect(url_for("auth.login")) |
| 35 | + g.user = session.get("user") |
| 36 | + return f(*args, **kwargs) |
17 | 37 |
|
18 | | -@auth.route('/login') |
| 38 | + return decorated_function |
| 39 | + |
| 40 | + |
| 41 | +@auth.route("/login") |
19 | 42 | def login(): |
20 | | - return render_template('login.html') |
| 43 | + if session.get("authenticated"): |
| 44 | + return redirect(url_for("main.profile")) |
| 45 | + return render_template("login.html") |
21 | 46 |
|
22 | 47 |
|
23 | | -@auth.route('/authorize') |
| 48 | +@auth.route("/authorize") |
24 | 49 | def authorize(): |
25 | | - oauth = current_app.extensions['authlib.integrations.flask_client'] |
26 | | - gamma = oauth.gamma |
27 | | - |
28 | | - return gamma.authorize_redirect(redirect_uri) |
| 50 | + gamma = get_gamma() |
| 51 | + return gamma.authorize_redirect(url_for("auth.callback", _external=True)) |
29 | 52 |
|
30 | 53 |
|
31 | | -@auth.route('/api/auth/callbacks/gamma') |
| 54 | +@auth.route("/api/auth/callbacks/gamma") |
32 | 55 | def callback(): |
33 | | - oauth = current_app.extensions['authlib.integrations.flask_client'] |
34 | | - gamma = oauth.gamma |
35 | | - |
36 | | - # Get the access token from the callback |
| 56 | + gamma = get_gamma() |
| 57 | + |
37 | 58 | token = gamma.authorize_access_token() |
38 | | - |
39 | | - # Try to get user info |
| 59 | + |
40 | 60 | try: |
41 | | - user_info_response = gamma.get('/oauth2/userinfo', token=token) |
| 61 | + user_info_response = gamma.get("/oauth2/userinfo", token=token) |
42 | 62 | user_info = user_info_response.json() |
43 | | - print("=== USER INFO FROM GAMMA ===") |
44 | | - print(f"User info: {user_info}") |
45 | 63 | except Exception as e: |
46 | | - print(f"UserInfo API Exception: {e}") |
47 | | - # Fallback to basic info from token |
48 | 64 | user_info = { |
49 | | - 'message': 'UserInfo unavailable', |
50 | | - 'scopes': token.get('scope', 'N/A') |
| 65 | + "message": "UserInfo unavailable", |
| 66 | + "scopes": token.get("scope", "N/A"), |
51 | 67 | } |
52 | | - |
53 | | - # Add token scope info to user data for display |
54 | | - if 'scope' not in user_info and token.get('scope'): |
55 | | - user_info['scopes'] = token.get('scope') |
56 | | - |
57 | | - # Store only the most essential user info in session (reduce session size) |
| 68 | + |
| 69 | + if "scope" not in user_info and token.get("scope"): |
| 70 | + user_info["scopes"] = token.get("scope") |
| 71 | + |
58 | 72 | essential_user_info = { |
59 | | - 'sub': user_info.get('sub'), |
60 | | - 'name': user_info.get('name'), |
61 | | - 'email': user_info.get('email'), |
62 | | - 'cid': user_info.get('cid') |
| 73 | + "sub": user_info.get("sub"), |
| 74 | + "name": user_info.get("name"), |
| 75 | + "email": user_info.get("email"), |
| 76 | + "cid": user_info.get("cid"), |
63 | 77 | } |
64 | | - |
| 78 | + |
65 | 79 | # Store user info in session |
66 | | - session['user'] = essential_user_info |
| 80 | + session["user"] = essential_user_info |
67 | 81 | # Don't store the full token to save space |
68 | | - session['authenticated'] = True |
69 | | - |
70 | | - print("=== SESSION DATA ===") |
71 | | - print(f"User data stored in session: {essential_user_info}") |
72 | | - print(f"Token scopes: {token.get('scope', 'N/A')}") |
73 | | - print(f"Full user info: {user_info}") |
74 | | - |
75 | | - return redirect(url_for('main.profile')) |
| 82 | + session["authenticated"] = True |
| 83 | + |
| 84 | + return redirect(url_for("main.profile")) |
| 85 | + |
| 86 | + |
| 87 | +def clear_auth_session(): |
| 88 | + """ |
| 89 | + Clear authentication-related session data. |
| 90 | +
|
| 91 | + `user` and `authenticated` keys are removed from the session. |
| 92 | + """ |
| 93 | + session.pop("user", None) |
| 94 | + session.pop("authenticated", None) |
76 | 95 |
|
77 | 96 |
|
78 | | -@auth.route('/logout') |
| 97 | +@auth.route("/logout") |
79 | 98 | def logout(): |
80 | | - session.pop('user', None) |
81 | | - session.pop('authenticated', None) |
82 | | - return redirect(url_for('main.index')) |
| 99 | + clear_auth_session() |
| 100 | + return redirect(url_for("main.index")) |
0 commit comments