This is an automated email from the ASF dual-hosted git repository. rusackas pushed a commit to branch fix/jwt-auth-current-user-api in repository https://gitbox.apache.org/repos/asf/superset.git
commit e72324c7ea4116bc161bfeda8308a10f3eea1d91 Author: Evan Rusackas <[email protected]> AuthorDate: Wed Dec 3 09:48:21 2025 -0800 fix(api): Fix JWT authentication for /api/v1/me endpoints Add @protect() and @permission_name decorators to CurrentUserRestApi endpoints to properly handle JWT authentication. This fixes a longstanding issue where JWT tokens were not properly setting the user context, causing 401 errors. - Add @protect() decorator to handle both session and JWT auth - Add @permission_name decorators for proper permission management - Remove redundant authentication checks now handled by @protect() - Add allow_browser_login = True for consistency with other APIs Fixes: #19525 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> --- superset/views/users/api.py | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/superset/views/users/api.py b/superset/views/users/api.py index 83d95b1bf3..5f75b836eb 100644 --- a/superset/views/users/api.py +++ b/superset/views/users/api.py @@ -18,9 +18,9 @@ from datetime import datetime from typing import Any, Dict from flask import current_app as app, g, redirect, request, Response -from flask_appbuilder.api import expose, safe +from flask_appbuilder.api import expose, permission_name, safe +from flask_appbuilder.security.decorators import protect from flask_appbuilder.security.sqla.models import User -from flask_jwt_extended.exceptions import NoAuthorizationError from marshmallow import ValidationError from sqlalchemy.orm.exc import NoResultFound from werkzeug.security import generate_password_hash @@ -41,6 +41,7 @@ class CurrentUserRestApi(BaseSupersetApi): resource_name = "me" openapi_spec_tag = "Current User" + allow_browser_login = True openapi_spec_component_schemas = (UserResponseSchema, CurrentUserPutSchema) current_user_put_schema = CurrentUserPutSchema() @@ -56,6 +57,8 @@ class CurrentUserRestApi(BaseSupersetApi): ) @expose("/", methods=("GET",)) + @protect() + @permission_name("read") @safe def get_me(self) -> Response: """Get the user object corresponding to the agent making the request. @@ -78,15 +81,11 @@ class CurrentUserRestApi(BaseSupersetApi): 401: $ref: '#/components/responses/401' """ - try: - if g.user is None or g.user.is_anonymous: - return self.response_401() - except NoAuthorizationError: - return self.response_401() - return self.response(200, result=user_response_schema.dump(g.user)) @expose("/roles/", methods=("GET",)) + @protect() + @permission_name("read") @safe def get_my_roles(self) -> Response: """Get the user roles corresponding to the agent making the request. @@ -109,15 +108,12 @@ class CurrentUserRestApi(BaseSupersetApi): 401: $ref: '#/components/responses/401' """ - try: - if g.user is None or g.user.is_anonymous: - return self.response_401() - except NoAuthorizationError: - return self.response_401() user = bootstrap_user_data(g.user, include_perms=True) return self.response(200, result=user) @expose("/", methods=["PUT"]) + @protect() + @permission_name("write") @safe @statsd_metrics @event_logger.log_this_with_context( @@ -153,11 +149,6 @@ class CurrentUserRestApi(BaseSupersetApi): 401: $ref: '#/components/responses/401' """ - try: - if g.user is None or g.user.is_anonymous: - return self.response_401() - except NoAuthorizationError: - return self.response_401() try: item = self.current_user_put_schema.load(request.json) if not item:
