From a6834f089bc2980fced99a617670e785c988cc9f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 24 Aug 2026 17:47:10 -0400 Subject: [PATCH] refac --- backend/open_webui/models/users.py | 12 ++++++++++-- backend/open_webui/routers/auths.py | 9 ++++++++- backend/open_webui/utils/oauth.py | 11 +++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/backend/open_webui/models/users.py b/backend/open_webui/models/users.py index 1cfbf5cb29..3d132c529e 100644 --- a/backend/open_webui/models/users.py +++ b/backend/open_webui/models/users.py @@ -360,9 +360,14 @@ class UsersTable: db: AsyncSession | None = None, ) -> UserModel | None: """Look up a user by OAuth provider + subject claim.""" + sub = str(sub) async with get_async_db_context(db) as session: # Subscript, never contains(): on a JSON column contains() degrades to a substring LIKE. - query = select(User).where(User.oauth[provider]['sub'].as_string() == sub) + sub_expr = User.oauth[provider]['sub'].as_string() + query = select(User).where(sub_expr == sub) + # SQLite preserves JSON numeric type here; Postgres ->> already compares numeric JSON as text. + if session.get_bind().dialect.name == 'sqlite' and sub.isdecimal(): + query = select(User).where(or_(sub_expr == sub, sub_expr == int(sub))) row = (await session.execute(query)).scalars().first() return UserModel.model_validate(row) if row else None @@ -677,7 +682,10 @@ class UsersTable: if not user: return None oauth = dict(user.oauth or {}) - oauth[provider] = {'sub': sub} + provider_oauth = oauth.get(provider) + provider_oauth = dict(provider_oauth) if isinstance(provider_oauth, dict) else {} + provider_oauth['sub'] = str(sub) + oauth[provider] = provider_oauth user.oauth = oauth await session.commit() return UserModel.model_validate(user) diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index d3cdcb162d..e0085b73fd 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -1671,6 +1671,7 @@ async def token_exchange( status_code=status.HTTP_400_BAD_REQUEST, detail="Token missing required 'sub' claim", ) + sub = str(sub) email = user_data.get(email_claim, '') if not email: @@ -1700,7 +1701,13 @@ async def token_exchange( user = await Users.get_user_by_email(email, db=db) if user: # Link the OAuth sub to this user - await Users.update_user_oauth_by_id(user.id, provider, sub, db=db) + user = await Users.update_user_oauth_by_id(user.id, provider, sub, db=db) or user + + if user: + provider_oauth = (user.oauth or {}).get(provider) if isinstance(user.oauth, dict) else None + # Lazy repair for legacy rows that stored numeric provider ids as JSON numbers. + if isinstance(provider_oauth, dict) and provider_oauth.get('sub') != sub: + user = await Users.update_user_oauth_by_id(user.id, provider, sub, db=db) or user if not user: raise HTTPException( diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index 278ff9e2e6..05b67d1f78 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -1929,6 +1929,7 @@ class OAuthManager: if not sub: log.warning(f'OAuth callback failed, sub is missing: {user_data}') raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED) + sub = str(sub) oauth_data = {} oauth_data[provider] = { @@ -1993,7 +1994,13 @@ class OAuthManager: user = await Users.get_user_by_email(email, db=db) if user: # Update the user with the new oauth sub - await Users.update_user_oauth_by_id(user.id, provider, sub, db=db) + user = await Users.update_user_oauth_by_id(user.id, provider, sub, db=db) or user + + if user: + provider_oauth = (user.oauth or {}).get(provider) if isinstance(user.oauth, dict) else None + # Lazy repair for legacy rows that stored numeric provider ids as JSON numbers. + if isinstance(provider_oauth, dict) and provider_oauth.get('sub') != sub: + user = await Users.update_user_oauth_by_id(user.id, provider, sub, db=db) or user if user: user = await self.update_user_role_from_oauth( @@ -2377,7 +2384,7 @@ class OAuthManager: # 8. Identify users to log out users_to_logout = [] if sub: - user = await Users.get_user_by_oauth_sub(matched_provider, sub, db=db) + user = await Users.get_user_by_oauth_sub(matched_provider, str(sub), db=db) if user: users_to_logout.append(user)