You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@superset.apache.org by "byeonghyun-kim (via GitHub)" <gi...@apache.org> on 2025/09/26 06:07:30 UTC
Re: [I] Endpoint /api/me/roles returns 401 "Not authorized" despite valid access token [superset]
byeonghyun-kim commented on issue #25740:
URL: https://github.com/apache/superset/issues/25740#issuecomment-3336901186
Maybe this issue is inactive, but I also ran into it when primarily using Keycloak as AUTH_OAUTH. It turns out that the JWT token from login only have 'sub' field, which is user id value itself. When calling /api/v1/me or other APIs, somehow this 'sub' based user lookup method does not work properly.
When you call the API and check the logs in the WebUI, the API calls may show a 'None' user, meaning that fetching user from access token failed.
With the help of GPT and inspecting the codebase, adding custom security manager did the trick. Now I can finally maintain Keycloak login session, but if I need to use DB login for the API, that still works as well.
I'm currently using 4.1.2 version, and it works.
Be sure that you turned on AUTH_API_LOGIN_ALLOW_MULTIPLE_PROVIDERS option as True, just in case of preventing collision of providers.
```
import re, jwt
from flask import current_app
from superset.security import SupersetSecurityManager
class ApiFirstSecurityManager(SupersetSecurityManager):
def __init__(self, appbuilder):
super().__init__(appbuilder)
lm = self.lm
@lm.request_loader
def bearer_request_loader(req):
"""
1) Authorization: Find jwt token with regex in Bearer <jwt> from authorization header and load user
2) If user is empty or fail, return None → Flask-Login uses default location such as user_loader
"""
auth = req.headers.get("Authorization", "")
m = re.match(r"^\s*Bearer\s+(.+)$", auth, re.I)
if not m:
return None
token = m.group(1)
secret = (current_app.config.get("SECRET_KEY")
or current_app.config.get("SUPERSET_SECRET_KEY"))
alg = current_app.config.get("JWT_ALGORITHM", "HS256") # this may fallback to HS256 in default, 4.1.2 doesn't have 'JWT_ALGORITHM' config value
try:
payload = jwt.decode(token, secret, algorithms=[alg])
except Exception:
return None
uid = payload.get("sub")
username = payload.get("username")
user = self.get_user_by_id(uid) if uid is not None else None
if user is None and username: # jwt token only have 'sub' as uid but just in case
user = self.find_user(username=username)
return user
```
Add this code to superset_config.py (you can separate code as another python file of course)
and set CUSTOM_SECURITY_MANAGER = ApiFirstSecurityManager and re-deploy.
Now the API using access token can search user itself.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org