feat: add reverse proxy support with HTTPS configuration
This commit is contained in:
@@ -27,6 +27,12 @@ LASTFM_API_KEY=your-lastfm-api-key
|
||||
SQLALCHEMY_DATABASE_URI=sqlite:///data/song_data.db
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS=False
|
||||
|
||||
# HTTPS Configuration (for reverse proxy environments)
|
||||
# Set to True when running behind a reverse proxy with HTTPS offloading (e.g., Traefik)
|
||||
USE_HTTPS=False
|
||||
# Uncomment and set to 'https' for production environments behind HTTPS proxy
|
||||
# PREFERRED_URL_SCHEME=https
|
||||
|
||||
# Spotify API configuration
|
||||
SPOTIFY_CLIENT_ID=your-spotify-client-id
|
||||
SPOTIFY_CLIENT_SECRET=your-spotify-client-secret
|
||||
|
||||
@@ -111,6 +111,10 @@ def create_app(config=None):
|
||||
# Configure the app
|
||||
app.config.from_object(Config)
|
||||
|
||||
# Set preferred URL scheme for reverse proxy support
|
||||
if app.config.get('USE_HTTPS'):
|
||||
app.config['PREFERRED_URL_SCHEME'] = 'https'
|
||||
|
||||
# Explicitly set the database URI to ensure correct path
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}'
|
||||
|
||||
|
||||
@@ -71,5 +71,9 @@ class Config:
|
||||
# Automation settings
|
||||
AUTOMATION_TOKEN = os.getenv("AUTOMATION_TOKEN", "change-this-token-in-production")
|
||||
|
||||
# Reverse proxy settings
|
||||
USE_HTTPS = os.getenv("USE_HTTPS", "False") == "True" # Force HTTPS URL generation
|
||||
PREFERRED_URL_SCHEME = 'https' if USE_HTTPS else 'http'
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -344,4 +344,14 @@ def update_oauth_tokens(user, tokens, auth_provider):
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
current_app.logger.error(f"Error updating {auth_provider} tokens: {str(e)}")
|
||||
return False
|
||||
return False
|
||||
|
||||
def get_oauth_redirect_uri(endpoint, provider=None):
|
||||
"""
|
||||
Generate OAuth redirect URI with proper scheme handling for reverse proxy environments
|
||||
"""
|
||||
# Use Flask's url_for which respects PREFERRED_URL_SCHEME
|
||||
if provider:
|
||||
return url_for(endpoint, provider=provider, _external=True)
|
||||
else:
|
||||
return url_for(endpoint, _external=True)
|
||||
@@ -2,6 +2,7 @@
|
||||
Helpers for Dropbox API integration
|
||||
"""
|
||||
from flask import current_app, url_for, redirect, session
|
||||
from musicround.helpers.auth_helpers import get_oauth_redirect_uri
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
@@ -11,7 +12,7 @@ from flask_login import current_user
|
||||
def get_dropbox_auth_url():
|
||||
"""Get the authorization URL for Dropbox OAuth flow"""
|
||||
app_key = current_app.config.get('DROPBOX_APP_KEY')
|
||||
redirect_uri = url_for('users.dropbox_callback', _external=True)
|
||||
redirect_uri = get_oauth_redirect_uri('users.dropbox_callback')
|
||||
|
||||
# Add the required scopes for our application
|
||||
scopes = ["files.content.read", "files.content.write", "sharing.write","account_info.read"]
|
||||
@@ -23,7 +24,7 @@ def exchange_code_for_token(code):
|
||||
"""Exchange the authorization code for an access token"""
|
||||
app_key = current_app.config.get('DROPBOX_APP_KEY')
|
||||
app_secret = current_app.config.get('DROPBOX_APP_SECRET')
|
||||
redirect_uri = url_for('users.dropbox_callback', _external=True)
|
||||
redirect_uri = get_oauth_redirect_uri('users.dropbox_callback')
|
||||
|
||||
data = {
|
||||
'code': code,
|
||||
|
||||
@@ -9,7 +9,7 @@ from musicround.models import User, db
|
||||
from datetime import datetime
|
||||
import requests
|
||||
import secrets
|
||||
from musicround.helpers.auth_helpers import oauth, find_or_create_user, update_oauth_tokens, get_spotify_user_info
|
||||
from musicround.helpers.auth_helpers import oauth, find_or_create_user, update_oauth_tokens, get_spotify_user_info, get_oauth_redirect_uri
|
||||
|
||||
# Create blueprint
|
||||
auth_bp = Blueprint('auth', __name__)
|
||||
@@ -37,7 +37,7 @@ def login_with_spotify():
|
||||
return redirect(url_for('users.login'))
|
||||
|
||||
# The redirect URI should point to *this* blueprint's callback
|
||||
redirect_uri = url_for('auth.callback', _external=True)
|
||||
redirect_uri = get_oauth_redirect_uri('auth.callback')
|
||||
|
||||
# Ensure 'show_dialog': 'true' is part of authorize_params in auth_helpers.py
|
||||
# when registering the Spotify client.
|
||||
|
||||
@@ -11,7 +11,7 @@ from sqlalchemy.exc import IntegrityError
|
||||
|
||||
from musicround.models import db, User, Role, SystemSetting
|
||||
from musicround.helpers.utils import get_available_voices
|
||||
from musicround.helpers.auth_helpers import oauth, find_or_create_user, update_oauth_tokens, get_google_user_info, get_authentik_user_info, get_spotify_user_info
|
||||
from musicround.helpers.auth_helpers import oauth, find_or_create_user, update_oauth_tokens, get_google_user_info, get_authentik_user_info, get_spotify_user_info, get_oauth_redirect_uri
|
||||
from musicround.helpers.spotify_helper import get_spotify_token, get_current_user_spotify_token, get_spotify_user_info as spotify_helper_get_user_info
|
||||
|
||||
users_bp = Blueprint('users', __name__, url_prefix='/users')
|
||||
@@ -72,14 +72,12 @@ def admin_required(f):
|
||||
def google_login():
|
||||
"""Initiate Google OAuth login flow"""
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('core.index'))
|
||||
|
||||
# Google login is disabled if client ID is not set
|
||||
return redirect(url_for('core.index')) # Google login is disabled if client ID is not set
|
||||
if not current_app.config.get('GOOGLE_CLIENT_ID'):
|
||||
flash('Google login is not configured.', 'danger')
|
||||
return redirect(url_for('users.login'))
|
||||
|
||||
redirect_uri = url_for('users.google_callback', _external=True)
|
||||
redirect_uri = get_oauth_redirect_uri('users.google_callback')
|
||||
return oauth.google.authorize_redirect(redirect_uri)
|
||||
|
||||
@users_bp.route('/login/google/callback')
|
||||
@@ -128,14 +126,12 @@ def google_callback():
|
||||
def authentik_login():
|
||||
"""Initiate Authentik OAuth login flow"""
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('core.index'))
|
||||
|
||||
# Authentik login is disabled if client ID is not set
|
||||
return redirect(url_for('core.index')) # Authentik login is disabled if client ID is not set
|
||||
if not current_app.config.get('AUTHENTIK_CLIENT_ID'):
|
||||
flash('Authentik login is not configured.', 'danger')
|
||||
return redirect(url_for('users.login'))
|
||||
|
||||
redirect_uri = url_for('users.authentik_callback', _external=True)
|
||||
redirect_uri = get_oauth_redirect_uri('users.authentik_callback')
|
||||
return oauth.authentik.authorize_redirect(redirect_uri)
|
||||
|
||||
@users_bp.route('/login/authentik/callback')
|
||||
@@ -756,15 +752,14 @@ The Quizzical Beats Team
|
||||
@login_required
|
||||
def spotify_link():
|
||||
"""
|
||||
GET: Show management UI (manage_spotify.html) with current status and options.
|
||||
POST: Trigger Spotify OAuth flow for linking/re-linking.
|
||||
GET: Show management UI (manage_spotify.html) with current status and options. POST: Trigger Spotify OAuth flow for linking/re-linking.
|
||||
"""
|
||||
if request.method == 'POST':
|
||||
# Only POST triggers the OAuth flow
|
||||
if not current_app.config.get('SPOTIFY_CLIENT_ID'):
|
||||
flash('Spotify integration is not configured.', 'danger')
|
||||
return redirect(url_for('users.spotify_link')) # Redirect to spotify_link page
|
||||
redirect_uri = url_for('users.spotify_link_callback', _external=True)
|
||||
redirect_uri = get_oauth_redirect_uri('users.spotify_link_callback')
|
||||
return oauth.spotify.authorize_redirect(redirect_uri, show_dialog='true')
|
||||
|
||||
# GET: Show management UI
|
||||
|
||||
Reference in New Issue
Block a user