refac: oauth session management
This commit is contained in:
@@ -557,6 +557,12 @@ OAUTH_SESSION_TOKEN_ENCRYPTION_KEY = os.environ.get(
|
|||||||
"OAUTH_SESSION_TOKEN_ENCRYPTION_KEY", WEBUI_SECRET_KEY
|
"OAUTH_SESSION_TOKEN_ENCRYPTION_KEY", WEBUI_SECRET_KEY
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Maximum number of concurrent OAuth sessions per user per provider
|
||||||
|
# This prevents unbounded session growth while allowing multi-device usage
|
||||||
|
OAUTH_MAX_SESSIONS_PER_USER = int(
|
||||||
|
os.environ.get("OAUTH_MAX_SESSIONS_PER_USER", "10")
|
||||||
|
)
|
||||||
|
|
||||||
# Token Exchange Configuration
|
# Token Exchange Configuration
|
||||||
# Allows external apps to exchange OAuth tokens for OpenWebUI tokens
|
# Allows external apps to exchange OAuth tokens for OpenWebUI tokens
|
||||||
ENABLE_OAUTH_TOKEN_EXCHANGE = (
|
ENABLE_OAUTH_TOKEN_EXCHANGE = (
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ class OAuthSessionTable:
|
|||||||
session = (
|
session = (
|
||||||
db.query(OAuthSession)
|
db.query(OAuthSession)
|
||||||
.filter_by(provider=provider, user_id=user_id)
|
.filter_by(provider=provider, user_id=user_id)
|
||||||
|
.order_by(OAuthSession.created_at.desc())
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
if session:
|
if session:
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ from open_webui.env import (
|
|||||||
ENABLE_OAUTH_ID_TOKEN_COOKIE,
|
ENABLE_OAUTH_ID_TOKEN_COOKIE,
|
||||||
ENABLE_OAUTH_EMAIL_FALLBACK,
|
ENABLE_OAUTH_EMAIL_FALLBACK,
|
||||||
OAUTH_CLIENT_INFO_ENCRYPTION_KEY,
|
OAUTH_CLIENT_INFO_ENCRYPTION_KEY,
|
||||||
|
OAUTH_MAX_SESSIONS_PER_USER,
|
||||||
)
|
)
|
||||||
from open_webui.utils.misc import parse_duration
|
from open_webui.utils.misc import parse_duration
|
||||||
from open_webui.utils.auth import get_password_hash, create_token
|
from open_webui.utils.auth import get_password_hash, create_token
|
||||||
@@ -1679,11 +1680,23 @@ class OAuthManager:
|
|||||||
if "expires_in" in token and "expires_at" not in token:
|
if "expires_in" in token and "expires_at" not in token:
|
||||||
token["expires_at"] = datetime.now().timestamp() + token["expires_in"]
|
token["expires_at"] = datetime.now().timestamp() + token["expires_in"]
|
||||||
|
|
||||||
# Clean up any existing sessions for this user/provider first
|
# Enforce max concurrent sessions per user/provider to prevent
|
||||||
|
# unbounded growth while allowing multi-device usage
|
||||||
sessions = OAuthSessions.get_sessions_by_user_id(user.id, db=db)
|
sessions = OAuthSessions.get_sessions_by_user_id(user.id, db=db)
|
||||||
for session in sessions:
|
provider_sessions = sorted(
|
||||||
if session.provider == provider:
|
[
|
||||||
OAuthSessions.delete_session_by_id(session.id, db=db)
|
for session in sessions
|
||||||
|
if session.provider == provider
|
||||||
|
],
|
||||||
|
key=lambda session: session.created_at,
|
||||||
|
reverse=True,
|
||||||
|
)
|
||||||
|
# Keep the newest sessions up to the limit, prune the rest
|
||||||
|
if len(provider_sessions) >= OAUTH_MAX_SESSIONS_PER_USER:
|
||||||
|
for old_session in provider_sessions[
|
||||||
|
OAUTH_MAX_SESSIONS_PER_USER - 1 :
|
||||||
|
]:
|
||||||
|
OAuthSessions.delete_session_by_id(old_session.id, db=db)
|
||||||
|
|
||||||
session = OAuthSessions.create_session(
|
session = OAuthSessions.create_session(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
|
|||||||
Reference in New Issue
Block a user