mirror of
https://github.com/open-webui/open-webui.git
synced 2026-05-06 10:58:17 -05:00
[GH-ISSUE #21152] issue: Access to API with JWT token #19401
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Sechma on GitHub (Feb 4, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/21152
Check Existing Issues
Installation Method
Git Clone
Open WebUI Version
v0.7.2
Ollama Version (if applicable)
No response
Operating System
Windows 11
Browser (if applicable)
No response
Confirmation
README.md.Expected Behavior
If I don’t want users with the “user” role to access the API (because I want to protect my resources), I set Enable API Keys to False in /admin/settings/general, and at the same time in /admin/users/groups under Function Permissions I have API Keys set to False.
With API Keys set to False, I expect that a user will not be able to call API endpoints such as:
/api/chat/completions
Actual Behavior
I found a way for a user to access the API using a JWT token. The problem is that by doing so, the user can bypass, for example, Langfuse logging. This creates an opportunity to generate a large number of tokens without the ability to identify which user caused it.
Steps to Reproduce
Logs & Screenshots
Call the auth endpoint, for example:
curl -X POST "http://localhost:3000/api/v1/auths/signin" \ -H "Content-Type: application/json" \ -d '{ "email": "test@test.com", "password": "test" }'Response
: { ... token: [JWT TOKEN.].. }After that
Response:
{"id":"chatcmpl-D5V5G3604pG29yFtdPoY7b2EveaZA","object":"chat.completion","created":1770203498,"model":"gpt-4.1-2025-04-14","choices":[{"index":0,"message":{"role":"assistant","content":"Auth test received! ✅ \nI'm here and ready to assist. How can I help you today?","refusal":null,"annotations":[]},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":9,"completion_tokens":20,"total_tokens":29,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"service_tier":"default","system_fingerprint":"fp_6deacce395"}
Additional Information
The problem is infascturue is using same endpoints for the GUI and also for API
I suggest make the middleware which can solve this.
I will do also the PR for that.
@owui-terminator[bot] commented on GitHub (Feb 4, 2026):
🔍 Similar Issues Found
I found some existing issues that might be related to this one. Please check if any of these are duplicates or contain helpful solutions:
#20842 issue: Critical Security Issue - JWT Token Authentication Bypass for API Endpoints
by HarukenM123 • Jan 21, 2026 •
bug#20901 issue: Upgrade to 0.7.2 breaks API access
by huornlmj • Jan 23, 2026 •
bug#20942 issue: Previously working API keys now generating new "Internal server error" messages, JWT works ok.
by huornlmj • Jan 26, 2026 •
bug#20802 issue: oauth_token passed to tools is None
by m1g32 • Jan 19, 2026 •
bug#19823 Issue: MCP with OAuth 2.1 Authorization/Token retrival is broken in v0.6.41
by mllab-nl • Dec 08, 2025 •
bugShow 1 more related issues
by pvutov • Dec 12, 2025 •
bug💡 Tips:
This comment was generated automatically by a bot. Please react with a 👍 if this comment was helpful, or a 👎 if it was not.
@Classic298 commented on GitHub (Feb 4, 2026):
P L E A S E
SEARCH FOR EXISTING ISSUES
P L E A S E
this was reported as "security incident" and as normal issues dozens of times
And no it does not make sense to add another JWT-standalone API
And how would one even do that? the JWT needs access to all api endpoints otherwise the chat interface does not work
PLEASE SEARCH FOR EXISTING ISSUES and read the docs.
@Classic298 commented on GitHub (Feb 4, 2026):
The bot even referenced the exact other issue that was opened recently. It would not have been hard to search before you open yet another issue
@Sechma commented on GitHub (Feb 4, 2026):
Thank you for the quick response.!!!
this is absolutely intended. The frontend uses the same api endpoints as the API key. Why not? The JWT needs access to chat completions. It's a chat interface!
Absolutely, but... I don't want users to be able to access the API via a JWT token, which they can regenerate at any time after expiration. All filters and logging are performed in an outlet that is triggered after /completed, so from an administration perspective, I lose control over logging with this approach.
I suggest this
It's simple middleware to prevent using JWT Bearer tokens (obtained via /api/v1/auths/signin) for external API calls. JWT tokens are now only allowed for:
Same-origin requests (the web GUI)
Auth endpoints (/api/v1/auths/)
Static resources (/ws, /static, /favicon)
External API callers must use API keys (sk-) for endpoints like /api/chat/completions. This mitigates token leakage risks by ensuring session JWTs cannot be used from external scripts.
@YetheSamartaka commented on GitHub (Feb 4, 2026):
I also see this as an security / administration issue how currently Open WebUI handles these endpoins and the fact that JWT can be used that way when it really shouldn't. Perhaps @Classic298 is not actually seeing the main problem. Or do you think that it is okay that user which does not have access to the API can still call it by providing his JWT? Is this intended?
@Classic298 commented on GitHub (Feb 4, 2026):
@YetheSamartaka how else is the user supposed to use the frontend? if you guys block the completions endpoint, then the chat interface will no longer work.
All the interface does is also just call the backend API.
There is no difference if you do it via script or via the frontend.
Both simply call the backend API
If you block completions endpoint for JWT then the frontend can no longer do chat messages.
Is this what you want?
@YetheSamartaka commented on GitHub (Feb 4, 2026):
@Classic298 Of course I want to do chat messages but also I don't want users to abuse the JWT via the API. Solution? I looked into the code that @Sechma mentioned and that middleware would essentially solve this -
584f2ec08cOr do you have any other ideas how to solve this situation?
@Classic298 commented on GitHub (Feb 4, 2026):
Your "solution" is trivially bypassable and not a solution at all
curl -X POST "http://localhost:3000/api/chat/completions"
-H "Origin: http://localhost:3000"
-H "Referer: http://localhost:3000/"
-H "Authorization: Bearer [JWT_TOKEN]"
...
Just add this header
done
Boom, you're "same-origin" now. These headers are not trustworthy for security decisions — they're just strings the client sends. This isn't CORS enforcement by the browser; it's server-side header checking that any HTTP client can fake.
You want to use Open WebUI for something it is not meant for.
Restricting the JWT access to the API WILL BREAK THE FRONTEND
And attempts like the one you proposed do not actually do what you want
@Classic298 commented on GitHub (Feb 4, 2026):
So once again
PLEASE UNDERSTAND how JWT works
Please understand what JWT is versus an API
PLEASE understand how Open WebUI works
PLEASE read the docs
and please do not say this is a security issue.
This is anything but a security issue. Neither confidentiality, nor integrity, not authenticity, nor availability, nor non-repeatability are being violated here
@Classic298 commented on GitHub (Feb 4, 2026):
What you actually probably want here is, let me guess - a feature request for more granular logging or that outlet() and inlet() filters get invoked - am i poking the right areas here?
@YetheSamartaka commented on GitHub (Feb 4, 2026):
I see your point and I did not want to upset you. I understand that this made you mad since this was reported many times before (It happens to me as well and it is very hard to keep it up for long hehe xD). However I still disagree that this is not a security issue. It is. Because I cannot restrict users to perform API calls. What if I want them to be able to chat with models ONLY via the Web UI? Currently, I cannot, right?
@Classic298 commented on GitHub (Feb 4, 2026):
@YetheSamartaka
No you cannot. Because the user HAS to access the API because the frontend uses the API.
The frontend authenticates the user using the JWT to the backend, runs completion() and returns result.
You can do the same thing via script.
ANY WEBSITE that uses JWT and has normal public endpoints allows their users to hypothetically call these endpoints and use these endpoints.
This is not a security issue, this is absolutely intended behaviour.
Ok lets do the following
Instead of describing a solution - describe your issue.
Do not jump to a solution that is not a solution - describe your issue. Describe what you want to do.
Chances are it's a feature request.
Because Open WebUI does not have an issue here and this is not a security issue either.
Describe what you want to do.
Then we can see if this even doable with Open WebUI (aka intended with it's intended usecase) or if there is another solution to what you want to do which you may not see.
@Sechma commented on GitHub (Feb 4, 2026):
From my point of view, it would be enough to just see usage logs.
If it’s not possible to limit it, then it would at least be sufficient to know who is generating high traffic over the API.
@Classic298 commented on GitHub (Feb 4, 2026):
@Sechma
what about using an inlet() filter here then?
outlet() is not called on a normal completion request, TRUE.
But inlet() is called even on normal API completion requests, always.
So you could add request logging there and even rate limiting by tracking the User email or user ID and having e.g. 100 request per day limit or similar.
@Classic298 commented on GitHub (Feb 4, 2026):
@YetheSamartaka does that work for you also?
@Classic298 commented on GitHub (Feb 4, 2026):
Theoretically you should even be able to check if the request in the inlet() has a chat id - and if not - reject the request....
@Classic298 commented on GitHub (Feb 4, 2026):
you can check for various things in the inlet(). Check if a chat id exists, check the toggled capabilities and much more.
And if any of them dont exist then just reject the request.
Is this bypassable?
It sure is. Someone who sends a carefully crafted request to the API can bypass these measures as well, but it's much more involved than adding a same origin header verification which you can bypass with a single line.
@Classic298 commented on GitHub (Feb 4, 2026):
chat_id
message_id
session_id
even "interface": "open-webui"
There is a lot of stuff you can test for in the filter inlet()
https://docs.openwebui.com/features/plugin/development/reserved-args/
Sure - not bulletproof either, but a MUCH larger burden than just a same origin check.
@Classic298 commented on GitHub (Feb 4, 2026):
If this works for you both, i will update the filter docs with more examples, one of them being rate limiting and logging requests - and also that the inlet() always gets called even on direct api requests wheras the outlet() does not.
@YetheSamartaka ?
@YetheSamartaka commented on GitHub (Feb 4, 2026):
I will answer in roughly 12-16 hours from now.
@YetheSamartaka commented on GitHub (Feb 5, 2026):
Hi @Classic298. Thank you for these follow-ups, I will try to lay it out in more detail. More examples in docs would be very helpful indeed. Perhaps it could be solved that way, but if the API way would trigger the same calls as user does via the UI, that would solve this since it would go through everything it is supposed to (regardless of the UI or API use, it should behave the same way, UI is just a representation of the answer, but the background things should go as usual)
Also another issue closely tied to this is as you've mentioned, the outlet not being called and I brought it up in this PR:
https://github.com/open-webui/open-webui/pull/18653
And also tasks were missing some metadata (Closed without any comments)
https://github.com/open-webui/open-webui/pull/19879/changes
As for the first PR I mentioned here, it also has a serious issue where when the chat is closed in the UI and left to be run in background, it does not trigger background things properly and that is huge oversight. Oversights that should be solved with priority instead of new features being added in imho. And this issue with JWT is kinda closely tied to this issue as well since the outlet is not properly called and other background things are borked as well.
Since you asked what are the issues to be fixed, I would sum it up in these points:
@Classic298 commented on GitHub (Feb 5, 2026):
Ok But all of this have ... little to do with the original issue at hand where you wanted to block the API from being accessed?
Your three points in the end basically boil down to
And once again - while you show some theoretical architectural weaknesses (Some of which I agree with, some of which i disagree with) - you have once again not described what you want to do. Maybe there are different solutions to your wishes and problems - or maybe, what you want to do, is simply not the specialty of open webui. Impossible to answer if you dont tell us what you want to do.
Especially since your three new wishes here are deviating quite a lot from the original topic which was just "block API requests from JWT"
@Classic298 commented on GitHub (Feb 5, 2026):
So your expansion of scope on this very issue here, which originally was about "JWT can access API" is ... not fitting
And I still dont know what you are trying to achieve exactly
@YetheSamartaka commented on GitHub (Feb 5, 2026):
One of the end results are to properly trigger functions (One of which is Langfuse function that is then storing info to Langfuse). And the usage with JWT bypasses these and those requests cannot be tracked that way.
@Classic298 commented on GitHub (Feb 5, 2026):
@YetheSamartaka so do you want to block JWT from accessing the API? Why does an inlet() with various checks if certain objects in the request data exist not suffice for you?
"JWT bypasses these and those requests cannot be tracked that way." in addition with your earlier statements sounds like you just want to block direct JWT requests to the API endpoints.
If you want to ALLOW requests to the API via JWT but still want to have the outlet() run everytime because only in the outlet() can you determine token usage - fine. That is valid. But that is a separate topic from this one here.
We are getting closer to a description of what you actually want to do, but we aren't quite there yet. You are still describing two scenarios in which both are problematic for you. In other words you are describing problems, not what you want to do.
@Classic298 commented on GitHub (Feb 5, 2026):
Converting this to discussion because this is a discussion now and the original issue of the issue is solved.