straight-lizard-48774
03/13/2025, 12:17 PMbrief-egg-61061
03/13/2025, 12:17 PMbrief-egg-61061
03/13/2025, 12:18 PMdecisions
endpoint located at the Ory Oathkeeper API port. [Introduction](https://www.ory.sh/docs/oathkeeper#access-control-decision-api) For Nginx specifically, Oathkeeper can integrate via "Authentication Based on Subrequest Result" as mentioned in the documentation: > Ory Oathkeeper's Access Control Decision API works with [...] [Nginx](https://www.nginx.com) via [Authentication Based on Subrequest Result](https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/) [Introduction](https://www.ory.sh/docs/oathkeeper) For Kubernetes Nginx Ingress, you would likely need to use the auth-url
annotation to point to Oathkeeper's Decision API endpoint (typically running at port 4456 as shown in the documentation). You would also need to configure which response headers from Oathkeeper should be passed to your upstream service using the auth-response-headers
annotation. Similar to the Traefik integration example provided in the documentation: # For Traefik: - traefik.http.middlewares.oathkeeper.forwardauth.address=<http://oathkeeper:4456/decisions> - traefik.http.middlewares.oathkeeper.forwardauth.authResponseHeaders=X-Id-Token,Authorization
[Traefik proxy integration](https://www.ory.sh/docs/oathkeeper/guides/traefik-proxy-integration) For Nginx Ingress, your annotations would look something like: yaml annotations: <http://nginx.ingress.kubernetes.io/auth-url|nginx.ingress.kubernetes.io/auth-url>: "<http://oathkeeper-service:4456/decisions>" <http://nginx.ingress.kubernetes.io/auth-response-headers|nginx.ingress.kubernetes.io/auth-response-headers>: "X-User,Authorization"
Note that you'll need to ensure: 1. Oathkeeper is properly configured with access rules 2. The Decision API is accessible from the Nginx Ingress controller 3. The appropriate headers are forwarded based on your mutator configuration The specific headers to include in auth-response-headers
will depend on which mutators you've configured in your Oathkeeper rules. I hope this helps! If you need more specific information about Nginx Ingress annotations, you might want to consult the Nginx Ingress documentation as well.straight-lizard-48774
03/13/2025, 12:21 PMapiVersion: <http://networking.k8s.io/v1|networking.k8s.io/v1>
kind: Ingress
metadata:
name: versa-cms-http-api
namespace: versa-platform-system
uid: 9af25917-5c8b-41bc-8d77-8add9c60d4e7
resourceVersion: '246543'
generation: 1
creationTimestamp: '2025-03-13T09:11:42Z'
labels:
<http://app.kubernetes.io/app|app.kubernetes.io/app>: versa-cms
<http://app.kubernetes.io/component|app.kubernetes.io/component>: http-api
<http://app.kubernetes.io/instance|app.kubernetes.io/instance>: http-api-m8558
<http://app.versa-stack.io/role|app.versa-stack.io/role>: api
<http://app.versa-stack.io/tier|app.versa-stack.io/tier>: service
<http://kustomize.toolkit.fluxcd.io/name|kustomize.toolkit.fluxcd.io/name>: http-api-m8558-xapplication-manifests
<http://kustomize.toolkit.fluxcd.io/namespace|kustomize.toolkit.fluxcd.io/namespace>: flux-system
annotations:
<http://cert-manager.io/cluster-issuer|cert-manager.io/cluster-issuer>: selfsigned-issuer
<http://kubernetes.io/ingress.class|kubernetes.io/ingress.class>: nginx
<http://nginx.ingress.kubernetes.io/auth-method|nginx.ingress.kubernetes.io/auth-method>: GET
<http://nginx.ingress.kubernetes.io/auth-response-headers|nginx.ingress.kubernetes.io/auth-response-headers>: Authorization
<http://nginx.ingress.kubernetes.io/auth-snippet|nginx.ingress.kubernetes.io/auth-snippet>: |
proxy_set_header X-Original-URL $request_uri;
proxy_set_header X-Forwarded-Method $request_method;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Uri $request_uri;
<http://nginx.ingress.kubernetes.io/auth-url|nginx.ingress.kubernetes.io/auth-url>: >-
<http://versa-platform-pd4jj-auth-oathkeeper-api.versa-platform-system.svc.cluster.local:4456/decisions>
selfLink: >-
/apis/networking.k8s.io/v1/namespaces/versa-platform-system/ingresses/versa-cms-http-api
status:
loadBalancer:
ingress:
- ip: 192.168.123.10
spec:
ingressClassName: nginx
tls:
- hosts:
- api.versa-stack.localdev
secretName: versa-cms-http-api-tls
rules:
- host: api.versa-stack.localdev
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: versa-cms-http-api
port:
name: http
but I keep getting an error in oathkeeper:
<http://github.com/urfave/negroni.HandlerFunc.ServeHTTP|github.com/urfave/negroni.HandlerFunc.ServeHTTP>
/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:29
<http://github.com/urfave/negroni.middleware.ServeHTTP|github.com/urfave/negroni.middleware.ServeHTTP>
/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38
<http://github.com/ory/x/reqlog.(*Middleware).ServeHTTP|github.com/ory/x/reqlog.(*Middleware).ServeHTTP>
/go/pkg/mod/github.com/ory/x@v0.0.677/reqlog/middleware.go:143
<http://github.com/urfave/negroni.middleware.ServeHTTP|github.com/urfave/negroni.middleware.ServeHTTP>
/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38
<http://github.com/ory/oathkeeper/metrics.(*Middleware).ServeHTTP|github.com/ory/oathkeeper/metrics.(*Middleware).ServeHTTP>
/project/metrics/middleware.go:105
<http://github.com/urfave/negroni.middleware.ServeHTTP|github.com/urfave/negroni.middleware.ServeHTTP>
/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38
<http://github.com/ory/x/metricsx.(*Service).ServeHTTP|github.com/ory/x/metricsx.(*Service).ServeHTTP>
/go/pkg/mod/github.com/ory/x@v0.0.677/metricsx/middleware.go:272
<http://github.com/urfave/negroni.middleware.ServeHTTP|github.com/urfave/negroni.middleware.ServeHTTP>
/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38
<http://github.com/urfave/negroni.(*Negroni).ServeHTTP|github.com/urfave/negroni.(*Negroni).ServeHTTP>
/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:96
<http://go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp.(*middleware).serveHTTP|go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp.(*middleware).serveHTTP>
/go/pkg/mod/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp@v0.57.0/handler.go:176
<http://go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp.NewMiddleware.func1.1|go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp.NewMiddleware.func1.1>
/go/pkg/mod/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp@v0.57.0/handler.go:65
net/http.HandlerFunc.ServeHTTP
/usr/local/go/src/net/http/server.go:2220
net/http.serverHandler.ServeHTTP
/usr/local/go/src/net/http/server.go:3210
net/http.(*conn).serve
/usr/local/go/src/net/http/server.go:2092
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1700 status:Internal Server Error status_code:500] http_request=map[headers:map[accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 accept-encoding:gzip, deflate, br, zstd accept-language:en-US,en;q=0.5 connection:close dnt:1 priority:u=0, i sec-fetch-dest:document sec-fetch-mode:navigate sec-fetch-site:none sec-fetch-user:?1 sec-gpc:1 upgrade-insecure-requests:1 user-agent:Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0 x-auth-request-redirect:/_status/alive x-forwarded-for:10.244.0.1 x-forwarded-host:api.versa-stack.localdev x-forwarded-method:GET x-forwarded-proto:https x-forwarded-uri:/_status/alive x-original-method:GET x-original-uri:/_status/alive x-original-url:<https://api.versa-stack.localdev/_status/alive> x-real-ip:10.244.0.1 x-request-id:1590a17b08562fffbf9b8069b2c61649 x-scheme:https x-sent-from:nginx-ingress-controller] host:versa-platform-pd4jj-auth-oathkeeper-api.versa-platform-system.svc.cluster.local method:GET path:/_status/alive query:<nil> remote:10.244.0.229:36880 scheme:http] http_response=map[status_code:500] service_name=ORY Oathkeeper service_version=v0.40.9
time=2025-03-13T12:06:07Z level=info msg=completed handling request http_request=map[headers:map[accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 accept-encoding:gzip, deflate, br, zstd accept-language:en-US,en;q=0.5 connection:close dnt:1 priority:u=0, i sec-fetch-dest:document sec-fetch-mode:navigate sec-fetch-site:none sec-fetch-user:?1 sec-gpc:1 upgrade-insecure-requests:1 user-agent:Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0 x-auth-request-redirect:/_status/alive x-forwarded-for:10.244.0.1 x-forwarded-host:api.versa-stack.localdev x-forwarded-method:GET x-forwarded-proto:https x-forwarded-uri:/_status/alive x-original-method:GET x-original-uri:/_status/alive x-original-url:<https://api.versa-stack.localdev/_status/alive> x-real-ip:10.244.0.1 x-request-id:1590a17b08562fffbf9b8069b2c61649 x-scheme:https x-sent-from:nginx-ingress-controller] host:versa-platform-pd4jj-auth-oathkeeper-api.versa-platform-system.svc.cluster.local method:GET path:/_status/alive query:<nil> remote:10.244.0.229:36880 scheme:http] http_response=map[headers:map[content-type:application/json] size:164 status:500 text_status:Internal Server Error took:344.378µs]
Loading...
and this is the rule that should be used for the request:
apiVersion: <http://oathkeeper.ory.sh/v1alpha1|oathkeeper.ory.sh/v1alpha1>
kind: Rule
metadata:
creationTimestamp: '2025-03-13T10:01:31Z'
finalizers:
- finalizer.oathkeeper.ory.sh
generation: 2
labels:
<http://app.kubernetes.io/app|app.kubernetes.io/app>: versa-cms
<http://app.kubernetes.io/component|app.kubernetes.io/component>: http-api
<http://app.kubernetes.io/instance|app.kubernetes.io/instance>: http-api-m8558
<http://app.versa-stack.io/engine|app.versa-stack.io/engine>: oathkeeper
<http://app.versa-stack.io/role|app.versa-stack.io/role>: auth
<http://app.versa-stack.io/tier|app.versa-stack.io/tier>: network
<http://kustomize.toolkit.fluxcd.io/name|kustomize.toolkit.fluxcd.io/name>: http-api-m8558-xapplication-manifests
<http://kustomize.toolkit.fluxcd.io/namespace|kustomize.toolkit.fluxcd.io/namespace>: flux-system
name: public-status
namespace: versa-platform-system
resourceVersion: '254691'
uid: 9a685546-2336-4c7b-bafd-8d6a34d8e62c
selfLink: >-
/apis/oathkeeper.ory.sh/v1alpha1/namespaces/versa-platform-system/rules/public-status
status:
validation:
valid: true
spec:
authenticators:
- handler: anonymous
authorizer:
handler: allow
match:
methods:
- GET
url: <https://api.versa-stack.localdev/_status><.*>
mutators:
- handler: noop
why am I getting the error?brief-egg-61061
03/13/2025, 12:21 PMbrief-egg-61061
03/13/2025, 12:21 PMtrust_forwarded_headers
setting doesn't tell Oathkeeper to use the X-Forwarded headers for matching rules, but rather to pass them to the outbound request. 2. URL Matching: Your rule is configured to match <https://api.versa-stack.localdev/_status<.*>>
, but the request is coming in with a path of /_status/alive
. The Decision API is receiving the request with headers like x-forwarded-host:api.versa-stack.localdev
and x-forwarded-uri:/_status/alive
, but it might not be properly using these headers for rule matching. 3. Missing Configuration: You might need to explicitly configure Oathkeeper to trust and use the forwarded headers for rule matching. Here are some suggestions to fix the issue: 1. Make sure your Oathkeeper configuration includes: yaml serve: proxy: trust_forwarded_headers: true
2. Try modifying your rule to match the exact path format that's coming in: yaml match: methods: - GET url: <http://versa-platform-pd4jj-auth-oathkeeper-api.versa-platform-system.svc.cluster.local:4456/_status<.*>>
Or alternatively, try a more generic pattern: yaml match: methods: - GET url: <http|https>://<.*>/_status<.*>
3. Check your Ingress annotation for the auth-url. You might want to ensure it's properly formatted and includes the /decisions
prefix: <http://nginx.ingress.kubernetes.io/auth-url|nginx.ingress.kubernetes.io/auth-url>: <http://versa-platform-pd4jj-auth-oathkeeper-api.versa-platform-system.svc.cluster.local:4456/decisions>
4. Consider adding more headers to your auth-response-headers
annotation if you're using any mutators that add headers. The issue might be related to how Oathkeeper processes the Decision API requests with forwarded headers, as highlighted in the GitHub issue. The Decision API should use the X-Forwarded headers, but there appears to be inconsistency in how this is implemented. If these suggestions don't resolve the issue, you might need to consider using the Host header approach instead of X-Forwarded headers, as that seems to work more reliably according to the GitHub issue comments.straight-lizard-48774
03/13/2025, 12:23 PMbrief-egg-61061
03/13/2025, 12:23 PMbrief-egg-61061
03/13/2025, 12:24 PMtoken_from
configuration not being respected. According to [this GitHub issue](https://github.com/ory/oathkeeper/issues/1144), when using a custom token header with the Decision API, the token isn't properly passed to the check_session_url
. This issue is specific to the Decision API and not the proxy. 2. The Decision API does actually use the X-Forwarded headers, unlike the proxy. As mentioned in [this GitHub issue](https://github.com/ory/oathkeeper/issues/1139): > "I dug some deeper and I see that the decision api uses the x
headers: https://github.com/ory/oathkeeper/blob/master/api/decision.go#L42" Based on your error logs, the issue appears to be with how the Decision API is processing the request. The 500 Internal Server Error suggests there might be a problem with how the rule is being matched or how the request is being processed internally. Given that the Decision API should be using the X-Forwarded headers correctly, the issue might be: 1. A mismatch between the URL format in your rule and how the Decision API is interpreting the forwarded URL 2. An internal error in Oathkeeper when processing the request 3. A potential issue with websocket connections, as mentioned in [this GitHub issue](https://github.com/ory/network/issues/76), where there were problems with websocket requests through Oathkeeper For your specific case, I'd recommend: 1. Check if your rule's URL pattern needs to be adjusted to match how the Decision API interprets the X-Forwarded headers 2. Look for more detailed error logs that might explain the 500 error 3. Consider simplifying your rule temporarily to see if a more basic configuration works Sorry for the confusion in my previous response. You're correct that the X-Forwarded headers issue is specific to the proxy mode, while the Decision API should be properly using these headers.straight-lizard-48774
03/13/2025, 12:25 PMbrief-egg-61061
03/13/2025, 12:25 PMbrief-egg-61061
03/13/2025, 12:26 PMX-Forwarded-Method
, X-Forwarded-Proto
, X-Forwarded-Host
, X-Forwarded-Uri
headers (if present) of the incoming request. [Introduction](https://www.ory.sh/docs/oathkeeper#decision-engine) Your rule should match the URL pattern that includes the forwarded host. Here's how it should look: yaml apiVersion: <http://oathkeeper.ory.sh/v1alpha1|oathkeeper.ory.sh/v1alpha1> kind: Rule metadata: name: public-status namespace: versa-platform-system spec: authenticators: - handler: anonymous authorizer: handler: allow match: methods: - GET url: <https://api.versa-stack.localdev/_status<.*>> mutators: - handler: noop
The key points to ensure proper matching: 1. The URL in the match section should use the exact hostname that's being forwarded in the X-Forwarded-Host header (in your case, "api.versa-stack.localdev") 2. The URL should include the proper scheme (https in your case, based on X-Forwarded-Proto) 3. The path pattern should match what's coming in the X-Forwarded-Uri header This approach ensures that Oathkeeper's Decision API will match the rule based on the forwarded request information rather than the direct request to the Oathkeeper API service. If you're still experiencing issues, you might want to check if there are any other rules that could be conflicting, or if there are any issues with how the headers are being forwarded from your Nginx Ingress controller.straight-lizard-48774
03/13/2025, 12:29 PMbrief-egg-61061
03/13/2025, 12:29 PMbrief-egg-61061
03/13/2025, 12:29 PMyaml apiVersion: <http://networking.k8s.io/v1|networking.k8s.io/v1> kind: Ingress metadata: name: versa-cms-http-api namespace: versa-platform-system annotations: <http://kubernetes.io/ingress.class|kubernetes.io/ingress.class>: nginx <http://nginx.ingress.kubernetes.io/auth-method|nginx.ingress.kubernetes.io/auth-method>: GET <http://nginx.ingress.kubernetes.io/auth-url|nginx.ingress.kubernetes.io/auth-url>: <http://versa-platform-pd4jj-auth-oathkeeper-api.versa-platform-system.svc.cluster.local:4456/decisions> <http://nginx.ingress.kubernetes.io/auth-response-headers|nginx.ingress.kubernetes.io/auth-response-headers>: Authorization <http://nginx.ingress.kubernetes.io/auth-snippet|nginx.ingress.kubernetes.io/auth-snippet>: | proxy_set_header X-Original-URL $request_uri; proxy_set_header X-Forwarded-Method $request_method; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Uri $request_uri; spec: ingressClassName: nginx tls: - hosts: - api.versa-stack.localdev secretName: versa-cms-http-api-tls rules: - host: api.versa-stack.localdev http: paths: - path: / pathType: ImplementationSpecific backend: service: name: versa-cms-http-api port: name: http
Your current Ingress configuration looks mostly correct, but there are a few things to consider: 1. The auth-url
annotation is correctly pointing to the Oathkeeper Decision API endpoint with the /decisions
path. 2. The auth-snippet
is correctly setting all the necessary X-Forwarded headers that Oathkeeper's Decision API needs to match your rule. 3. Your rule is configured to match <https://api.versa-stack.localdev/_status<.*>>
, which aligns with the host in your Ingress configuration. The main issue might be that your rule is expecting HTTPS (`https://api.versa-stack.localdev/_status<.*>`), but depending on how your cluster is configured, the X-Forwarded-Proto might be coming through as HTTP instead of HTTPS at some point in the chain. If you're still experiencing issues, you might want to try modifying your rule to be more flexible with the scheme: yaml spec: match: methods: - GET url: <http|https>://api.versa-stack.localdev/_status<.*>
This would allow the rule to match regardless of whether the forwarded protocol is HTTP or HTTPS.straight-lizard-48774
03/13/2025, 12:43 PM[
{
"upstream": {
"url": "",
"preserve_host": false
},
"id": "http-api-m8558-public-routes.versa-platform-system",
"match": {
"url": "<https://api.versa-stack.localdev/api/routes><.*>",
"methods": [
"GET"
]
},
"authenticators": [
{
"handler": "anonymous"
}
],
"authorizer": {
"handler": "allow"
},
"mutators": [
{
"handler": "noop"
}
]
},
{
"upstream": {
"url": "",
"preserve_host": false
},
"id": "http-api-m8558-public-status.versa-platform-system",
"match": {
"url": "<https://api.versa-stack.localdev/_status><.*>",
"methods": [
"GET"
]
},
"authenticators": [
{
"handler": "anonymous"
}
],
"authorizer": {
"handler": "allow"
},
"mutators": [
{
"handler": "noop"
}
]
},
{
"upstream": {
"url": "",
"preserve_host": false
},
"id": "http-api-m8558-public-pages.versa-platform-system",
"match": {
"url": "<https://api.versa-stack.localdev/api/pages><.*>",
"methods": [
"GET"
]
},
"authenticators": [
{
"handler": "anonymous"
}
],
"authorizer": {
"handler": "allow"
},
"mutators": [
{
"handler": "noop"
}
]
},
{
"upstream": {
"url": "",
"preserve_host": false
},
"id": "http-api-m8558-authenticated-catch-all.versa-platform-system",
"match": {
"url": "<https://api.versa-stack.localdev/><.*>",
"methods": [
"GET",
"POST",
"PUT",
"DELETE"
]
},
"authenticators": [
{
"handler": "cookie_session"
}
],
"authorizer": {
"handler": "allow"
},
"mutators": [
{
"handler": "noop"
}
]
}
]
it seems because of the catch-all rule I always match more than one rule. how can I achieve a whitelist approach for rules? I want to set all paths to require authentication except for those that I choose not to bebrief-egg-61061
03/13/2025, 12:43 PMbrief-egg-61061
03/13/2025, 12:43 PMX-Forwarded-Method
, X-Forwarded-Proto
, X-Forwarded-Host
, X-Forwarded-Uri
headers (if present) of the incoming request. The request is denied if no access rules match. [Introduction](https://www.ory.sh/docs/oathkeeper#decision-engine) The problem is that when multiple rules match, Oathkeeper doesn't know which one to apply. To implement a whitelist approach (authenticate everything except specific paths), you have a few options: ### Option 1: Use the matching_strategy
configuration Oathkeeper supports different matching strategies. You can set the matching_strategy
to glob
in your configuration: yaml access_rules: matching_strategy: glob repositories: - file:///etc/config/oathkeeper/access-rules.yml
With glob matching, you can then order your rules from most specific to least specific, and Oathkeeper will use the first matching rule. ### Option 2: Modify your catch-all rule to exclude the public paths You can use negative lookahead in your regex pattern for the catch-all rule to exclude the paths you want to be public: json { "id": "http-api-m8558-authenticated-catch-all.versa-platform-system", "match": { "url": "<https://api.versa-stack.localdev/(?!(_status%7Capi/routes%7Capi/pages)).*>", "methods": [ "GET", "POST", "PUT", "DELETE" ] }, "authenticators": [ { "handler": "cookie_session" } ], "authorizer": { "handler": "allow" }, "mutators": [ { "handler": "noop" } ] }
This regex pattern (?!(_status|api/routes|api/pages)).*
will match any path that doesn't start with _status
, api/routes
, or api/pages
. ### Option 3: Use rule priority (if supported in your version) Some versions of Oathkeeper support rule priority. If your version supports it, you can add a priority field to your rules, with lower numbers having higher priority: json { "id": "public-status", "priority": 1, "match": { "url": "<https://api.versa-stack.localdev/_status<.*>>" } }, { "id": "authenticated-catch-all", "priority": 100, "match": { "url": "<https://api.versa-stack.localdev/<.*>>" } }
The most reliable approach is likely Option 2, using a negative lookahead pattern in your catch-all rule to exclude the public paths. This ensures that only one rule will match for any given request, avoiding the multiple-match error. Remember to test your configuration thoroughly after making changes to ensure all paths are properly secured or allowed as intended. [Introduction](https://www.ory.sh/docs/oathkeeper#decision-engine) [API access rules](https://www.ory.sh/docs/oathkeeper/api-access-rules#scoped-credentials)straight-lizard-48774
03/13/2025, 12:48 PMbrief-egg-61061
03/13/2025, 12:48 PMbrief-egg-61061
03/13/2025, 12:48 PMyaml errors: fallback: - json handlers: redirect: enabled: true config: to: <http://your-login-url.com/login> when: - error: - unauthorized - forbidden request: header: accept: # We only want to redirect browser requests, not API requests - text/html json: enabled: true config: verbose: true
This configuration tells Oathkeeper to: 1. Redirect to your login URL when the error is either "unauthorized" or "forbidden" 2. Only perform the redirect for browser requests (those with Accept: text/html
header) 3. Return JSON errors for all other requests (like API calls) [Zero Trust with Access Proxy guide](https://www.ory.sh/docs/kratos/guides/zero-trust-iap-proxy-identity-access-proxy#error-handling) shows this exact pattern being used with Kratos. You can add this configuration to your Oathkeeper configuration file. If you're using Kubernetes, you would add this to your Oathkeeper ConfigMap or Secret. The redirect URL should point to your login page, which could be a Kratos self-service login UI or any other authentication interface you're using. This approach ensures a good user experience where browser users are redirected to login, while API clients receive proper JSON error responses. Would you like more details on any specific part of this configuration?straight-lizard-48774
03/13/2025, 12:51 PMaccess request denied audience=application error=map[debug: message:Requested url does not match any rules reason: stack_trace
I think the regular expression you gave me is wrong?brief-egg-61061
03/13/2025, 12:51 PMbrief-egg-61061
03/13/2025, 12:51 PM<
and >
. The negative lookahead pattern I suggested doesn't follow this format, which is why your catch-all rule isn't matching anymore. According to the documentation: > Regular expressions are encapsulated in brackets < and >. The following example matches all paths of the domain `mydomain.com`: <https://mydomain.com/<.*>>
. [Oathkeeper API access rules](https://www.ory.sh/docs/oathkeeper/api-access-rules#access-rule-format) Let's correct the catch-all rule. Instead of using a negative lookahead, you should: 1. Keep your specific public path rules as they are 2. Modify your catch-all rule to use Oathkeeper's syntax: json { "id": "http-api-m8558-authenticated-catch-all.versa-platform-system", "match": { "url": "<https://api.versa-stack.localdev/<.*>>", "methods": [ "GET", "POST", "PUT", "DELETE" ] }, "authenticators": [ { "handler": "cookie_session" } ], "authorizer": { "handler": "allow" }, "mutators": [ { "handler": "noop" } } }
Then, to make this work with your whitelist approach, you need to ensure Oathkeeper is configured to use the correct matching strategy. As mentioned in the documentation, you can use the glob
matching strategy and ensure your rules are ordered from most specific to least specific: yaml access_rules: matching_strategy: glob repositories: - file:///etc/config/oathkeeper/access-rules.yml
With the glob
matching strategy, Oathkeeper will use the first matching rule, so your specific public path rules will take precedence over the catch-all rule if they're listed first. If you're still experiencing issues, you might need to check your Oathkeeper configuration to ensure it's using the correct matching strategy.straight-lizard-48774
03/13/2025, 12:53 PMbrief-egg-61061
03/13/2025, 12:53 PMbrief-egg-61061
03/13/2025, 12:53 PM<
and >
, but your pattern has mixed HTML entities (<
and >
) with actual brackets. 2. Oathkeeper doesn't support negative lookahead assertions ((?!...)
) in the way you're trying to use them within its URL matching patterns. According to the documentation: > Regular expressions are encapsulated in brackets < and >. The following example matches all paths of the domain `mydomain.com`: <https://mydomain.com/<.*>>
. [API access rules](https://www.ory.sh/docs/oathkeeper/api-access-rules#access-rule-format) For your use case of implementing a whitelist approach, the recommended solution is to: 1. Keep your specific public path rules (for _status
, api/routes
, api/pages
) as separate rules 2. Use a catch-all rule with the standard syntax: <https://api.versa-stack.localdev/<.*>>
3. Configure Oathkeeper to use the glob
matching strategy 4. Order your rules from most specific to least specific This way, the more specific public path rules will match first, and the catch-all rule will only apply to paths not covered by the specific rules. If you need more complex matching patterns, you might need to split your rules into multiple specific rules rather than trying to use advanced regex features that Oathkeeper doesn't support.