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:

Reply via email to