Skip to content

Commit a33d63d

Browse files
committed
refactor: streamline OAuth integration and improve session management
1 parent d40c3c7 commit a33d63d

File tree

3 files changed

+89
-83
lines changed

3 files changed

+89
-83
lines changed

project/__init__.py

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,38 @@
11
from flask import Flask
22
from dotenv import load_dotenv
33
from authlib.integrations.flask_client import OAuth
4+
from .auth import auth as auth_blueprint
5+
from .main import main as main_blueprint
46
import os
57

68

79
def create_app():
810
load_dotenv()
9-
GAMMA_ROOT = 'https://auth.chalmers.it'
10-
auth_uri = f'{GAMMA_ROOT}/oauth2/authorize'
11-
token_uri = f'{GAMMA_ROOT}/oauth2/token'
12-
jwks_uri = f'{GAMMA_ROOT}/oauth2/jwks'
13-
user_info_uri = f'{GAMMA_ROOT}/oauth2/userinfo'
14-
redirect_uri = 'http://127.0.0.1:5000/api/auth/callbacks/gamma'
15-
client_id = os.getenv('GAMMA_CLIENT_ID', '')
16-
client_secret = os.getenv('GAMMA_CLIENT_SECRET', '')
17-
18-
oauth = OAuth()
11+
gamma_root = os.getenv("GAMMA_ROOT", "https://auth.chalmers.it")
12+
client_id = os.getenv("GAMMA_CLIENT_ID", "")
13+
client_secret = os.getenv("GAMMA_CLIENT_SECRET", "")
14+
1915
app = Flask(__name__)
2016

21-
app.config['SECRET_KEY'] = os.getenv('APP_SECRET_KEY', '')
17+
app.config["SECRET_KEY"] = os.getenv("APP_SECRET_KEY", "")
2218

2319
# Initialize OAuth with the Flask app
2420
oauth = OAuth(app)
2521

2622
# Register Gamma OAuth client with proper JWKS URI
2723
oauth.register(
28-
name='gamma',
24+
name="gamma",
2925
client_id=client_id,
3026
client_secret=client_secret,
31-
access_token_url=token_uri,
32-
authorize_url=auth_uri,
33-
api_base_url=GAMMA_ROOT,
27+
api_base_url=gamma_root,
3428
client_kwargs={
35-
'scope': 'openid email profile', # Required scopes for Gamma
29+
"scope": "openid email profile", # Required scopes for Gamma
3630
},
37-
# Provide JWKS URI for JWT validation
38-
jwks_uri=jwks_uri,
39-
server_metadata_url=None, # Disable auto-discovery
31+
server_metadata_url=f"{gamma_root}/.well-known/openid-configuration",
4032
)
4133

42-
# blueprint for auth routes in our app
43-
from .auth import auth as auth_blueprint
4434
app.register_blueprint(auth_blueprint)
4535

46-
# blueprint for non-auth parts of app
47-
from .main import main as main_blueprint
4836
app.register_blueprint(main_blueprint)
4937

5038
return app

project/auth.py

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,100 @@
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+
)
310
from authlib.integrations.flask_client import OAuth
411
from dotenv import load_dotenv
512
import os
13+
from functools import wraps
14+
615

716
# Allow HTTP for local development (required for OAuth2Session)
8-
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
17+
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
918

1019
load_dotenv()
1120

12-
# Get redirect URI for OAuth callbacks
13-
redirect_uri = 'http://127.0.0.1:5000/api/auth/callbacks/gamma'
1421

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+
1629

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)
1737

18-
@auth.route('/login')
38+
return decorated_function
39+
40+
41+
@auth.route("/login")
1942
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")
2146

2247

23-
@auth.route('/authorize')
48+
@auth.route("/authorize")
2449
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))
2952

3053

31-
@auth.route('/api/auth/callbacks/gamma')
54+
@auth.route("/api/auth/callbacks/gamma")
3255
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+
3758
token = gamma.authorize_access_token()
38-
39-
# Try to get user info
59+
4060
try:
41-
user_info_response = gamma.get('/oauth2/userinfo', token=token)
61+
user_info_response = gamma.get("/oauth2/userinfo", token=token)
4262
user_info = user_info_response.json()
43-
print("=== USER INFO FROM GAMMA ===")
44-
print(f"User info: {user_info}")
4563
except Exception as e:
46-
print(f"UserInfo API Exception: {e}")
47-
# Fallback to basic info from token
4864
user_info = {
49-
'message': 'UserInfo unavailable',
50-
'scopes': token.get('scope', 'N/A')
65+
"message": "UserInfo unavailable",
66+
"scopes": token.get("scope", "N/A"),
5167
}
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+
5872
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"),
6377
}
64-
78+
6579
# Store user info in session
66-
session['user'] = essential_user_info
80+
session["user"] = essential_user_info
6781
# 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)
7695

7796

78-
@auth.route('/logout')
97+
@auth.route("/logout")
7998
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"))

project/main.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
from flask import Blueprint, render_template, session, redirect, url_for
1+
from flask import Blueprint, render_template, g
22

3-
main = Blueprint('main', __name__)
3+
from .auth import login_required
44

5+
main = Blueprint("main", __name__)
56

6-
@main.route('/')
7+
8+
@main.route("/")
79
def index():
8-
return render_template('index.html')
10+
return render_template("index.html")
911

1012

11-
@main.route('/profile')
13+
@main.route("/profile")
14+
@login_required
1215
def profile():
13-
user = session.get('user')
14-
if not user:
15-
return redirect(url_for('auth.login'))
16-
return render_template('profile.html', user=user)
16+
return render_template("profile.html", user=g.get("user"))

0 commit comments

Comments
 (0)