Repository navigation
Evaluation API returns 403 for cross-origin browser requests despite authentication.exclude.evaluation: true #6566
Description
We are running Flipt v2 behind Traefik and want to evaluate feature flags directly from browser applications.
Our Flipt configuration has authentication enabled globally, but explicitly excludes the evaluation API from authentication:
authentication:
required: true
exclude:
evaluation: trueCORS is handled by Traefik rather than by Flipt:
cors:
enabled: falseTraefik allows our frontend origins using a regex-based CORS configuration, because we have many frontend URLs and cannot maintain a list of individual origins:
accessControlAllowOriginListRegex:
- "^https://(.*\\.)?example\\.(com|de|es|at|nl)$"
- "^https://(.*\\.)?anotherexample\\.(com|de)$"We then call the evaluation endpoint directly from the browser on one of those allowed URLs (e.g. https://myfrontend.subdomain.example.com):
fetch('https://flipt.example.com/api/v1/evaluate/boolean', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
namespaceKey: 'default',
flagKey: 'some-flag',
entityId: 'test-user',
context: {},
}),
credentials: 'omit'
})The request is rejected with:
403 cross-origin request detected from Sec-Fetch-Site header
The browser sends:
Sec-Fetch-Site: same-sitewhich is expected because our frontend and Flipt are under the same registrable domain but have different origins.
Why this is a problem
We understand and support CSRF/cross-origin protection for authenticated and state-changing API endpoints.
However, the evaluation API is explicitly configured as unauthenticated via:
authentication.exclude.evaluation: trueFor a browser-based feature-flag use case, cross-origin access to the evaluation endpoint is expected.
Our reverse proxy already performs origin validation and CORS handling, including regex/wildcard-style matching. Requiring Flipt's trusted_origins to contain every individual frontend origin is not practical for our setup.
In other words, we would like to be able to express a policy such as:
Allow evaluation requests from:
https://*.example.com
https://*.example.de
https://*.example.es
...
without having to enumerate thousands of exact origins.
Current workaround attempts
We tested modifying/removing Sec-Fetch-Site in Traefik only for /api/v1/evaluate/*.
For example:
customRequestHeaders:
Sec-Fetch-Site: "same-origin"This works with an explicit list of trusted_origins but rewriting the header does not seem like a good solution.
We do not consider rewriting browser security headers at the reverse proxy to be a desirable production solution.
Expected behavior
When:
authentication:
required: true
exclude:
evaluation: trueis configured, we would expect the evaluation endpoint to be usable from browser clients when CORS/origin authorization is explicitly handled by the deployment.
Possible solutions could be:
- Respect
authentication.exclude.evaluationfor the cross-origin protection as well, or - Provide a configurable origin pattern/regex mechanism for the evaluation endpoint, or
- Provide a dedicated configuration option to disable cross-origin protection specifically for evaluation requests.
The important part is that this should be possible without disabling cross-origin protection globally and without maintaining thousands of exact trusted origins.
Environment
- Flipt: v2
- Deployment: Helm (
flipt-v2chart fromhttps://helm.flipt.io/) - Reverse proxy: Traefik
- Browser: Standard modern browser
- CORS: Handled by Traefik
- Evaluation endpoint:
POST /api/v1/evaluate
Question
Is this behavior intentional? If so, what is the recommended configuration for allowing browser-based cross-origin evaluation when authentication.exclude.evaluation: true is enabled and the allowed origins are managed externally by a reverse proxy?
Activity
github-actions commentedon Sep 22, 2026
Issue Health Check: Well scoped
Type: Bug report
This is a well-structured issue reporting that cross-origin browser requests to the evaluation endpoint return 403 even when authentication is explicitly excluded for evaluation. It includes complete reproduction steps, configuration details, expected behavior, and proposed solutions.
Thanks — this issue looks well scoped and ready for the maintainers to evaluate.
Need help with Flipt? Support the project through GitHub Sponsors or learn about Flipt Pro.
erka commentedon Sep 22, 2026
Hey @wgg-max. Thanks for your report.
I think that CORS is not directly related to authentication and
authentication.exclude.evaluation: truehas no impact on CORS.In your example the url is
https://flipt.example.com/api/v1/evaluate/booleanbut it's usuallyhttps://flipt.example.com/evaluate/v1/boolean. Are you rewriting it in traefik? What happens if you setcors.enable: truein Flipt?wgg-max commentedon Sep 23, 2026
Hey @erka! Thanks for the suggestions.
I tried both of your suggestions: Using
https://flipt.example.com/evaluate/v1/booleaninstead of/api/v1/evaluate/boolean, and enabling Flipt CORS withallowed_origins: "*". Both individually and in combination. Unfortunately, the behavior remains the same.I would like to clarify one point, though: the
403 cross-origin request detected from Sec-Fetch-Site headerresponse does not appear to be related to the CORS configuration.This is not a typical browser-side CORS rejection. The request reaches Flipt and Flipt itself returns an HTTP
403response based on theSec-Fetch-Siteheader:I traced the behavior further and found that it is controlled by
authentication.session.csrf. When I disable the CSRF protection there, the evaluation request succeeds and I get the expected non-403 response.The problem is that we do not want to disable CSRF protection globally. We still need the admin UI and the other authenticated/state-changing endpoints to remain protected.
So the question is whether there is a way to keep
authentication.session.csrfenabled for the admin and other protected endpoints while exempting the unauthenticated evaluation endpoints (authentication.exclude.evaluation: true) from this particular cross-origin/CSRF check.That would allow us to keep the rest of Flipt secured while using the evaluation API from browser applications whose origins are already validated and handled by our reverse proxy.
wgg-max commentedon Sep 23, 2026
As far as I can tell, this is the behavior of Go's standard-library
net/http.CrossOriginProtection. It checksSec-Fetch-Sitefor non-safe HTTP methods and rejects cross-origin requests unless the origin is explicitly trusted. In our case, the browser correctly sends:because the frontend and Flipt are on different origins but the same registrable domain.
This also explains why the behavior is specific to the evaluation endpoint: the evaluation API requires a POST request, so the request is subject to this cross-origin/CSRF protection. GET, HEAD, and OPTIONS are treated as safe methods and are not rejected by this particular check.
erka commentedon Sep 23, 2026
Yeah, you're right. We probably need to rework how the CSRF middleware is applied and take the auth excludes into account to make it work as you want.
pradhankukiran commentedon Sep 23, 2026
The guard is global in internal/cmd/http.go:191. The open setting only skips login in internal/cmd/grpc.go:347. So public flag checks still hit the guard. CORS and guard are separate and only exact origins pass. Would you accept scoping the guard by route so private calls stay guarded and public evaluation passes when the open setting is true.
fix: respect auth exclusion in cross-origin protection