Complex problem with traefik api and authetication middleware

Hi all,

I have a stack docker-compose with traefik and an apache server
I have several authentication middleware (authelia, keycloak with openID, etc..)
I have also a middleware without authetication
the 2 services are availaible via url traefik.domain.com and apache.domain.com
all middleware inclus CORS (accessControlAllowOriginList: "*")
everyting works fine except when my apache application is requesting traefik api : https://apache.domain.com/api --> https://traefik.domain.com/api/http/routers/"
then I get error , for example with authelia middleware : Uncaught SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
with the other middleware I have different error.
I don't know how to manage this problem

1 Like

Gotta love complex challenges :slight_smile:

So your Apache app (php?) at /api is requesting https://traefik.domain.com/api/http/routers/?

Where is the JSON error thrown? In your app? Can you output the non JSON?

Share your full Traefik static and dynamic config, and docker-compose.yml if used.

1 Like

The application is really simple html+js (one page). I wanted to show on a single page all http routers in traefik with the associated middleware. This information is not available on 1 page in traefik dashboard.
The idea is to have it on single page to be sure that I have associated a middleware with authentication in front of each service.
Also each host rule in traefik are converted to url hyperlink

Here is the java script


var apiUrl='https://traefik.mydomain.com/api/http/routers';
var request=new XMLHttpRequest();
request.open('GET',apiUrl,!0);
request.onload=function(){
  var data=JSON.parse(this.response);
  var table=document.createElement("table");
  var headerRow=table.insertRow(-1);
  headerRow.innerHTML = "<th>Number</th><th>URL</th><th>Router</th><th>Entrypoints</th><th>Rule</th><th>Middlewares</th><th>Service</th><th>Provider</th><th>Status</th>";
  for(var i=0;i<data.length;i++){
    var row=table.insertRow(-1);
    var cell = row.insertCell(-1); // Insert a cell in the first column for the row number
    cell.innerHTML = i; // Set the cell value to the loop counter
    var entrypoints = data[i].entryPoints.join(', '); // Join the entryPoints array into a string separated by commas
    var middlewares;
    if (Array.isArray(data[i].middlewares)) {
      middlewares = data[i].middlewares.join(', '); // Join the middlewares array into a string separated by commas
    } else {
      middlewares = data[i].middlewares;
    }
    var url = data[i].rule.replace(/\`\)/g, '').replace(/Host\(\`/g, '').replace(/ && PathPrefix\(`/g, '');
    if (url.startsWith("HostRegexp")) {
      url = url.replace(/.+/, ""); // Replace the content with an empty string
    } else {
      url = "https://" + url; // Add the "https://" prefix
    }
    row.innerHTML = "<td>" + i + "</td><td><a href='" + url + "'>" + url + "</a></td><td><a href='https://traefik.mydomain.com/api/http/routers/" + data[i].name + "'>" + data[i].name + "</a></td><td>" + entrypoints + "</td><td>" + data[i].rule + "</td><td><a href='https://traefik.mydomain.com/api/http/middlewares/" + data[i].middlewares + "'>" + data[i].middlewares + "</a></td><td><a href='https://traefik.mydomain.com/api/http/services/" + data[i].service + "@" + data[i].provider + "'>" + data[i].service + "</a></td><td>" + data[i].provider + "</td><td>" + data[i].status + "</td>";
  }
  
  document.getElementById("jsonTable").appendChild(table)
};
request.send();

Here is the HTML


> <!DOCTYPE html>
> <html>
>   <head>
>       <title>Simple Traefik Dashboard v2</title>
>       <link rel="stylesheet" type="text/css" href="style.css">
>   </head>
>   <body>
>     <div id="jsonTable">
>       <h1>Simple Traefik Dashboard v2</h1>
>     </div>
>     <script src="script.js"></script>
>   </body>
> </html>

I have also create a test.html which simply contains "this is a test"

Here is the result (webpage)

Simple Traefik Dashboard v2
Number	URL	Router	Entrypoints	Rule	Middlewares	Service	Provider	Status
0	https://apache.mydomain.com	Apache2_rtr@docker	https	Host(`apache.mydomain.com`)	chain-no-auth@file	Apache2_svc	docker	enabled
1	https://adminer.mydomain.com	adminer_rtr@docker	https	Host(`adminer.mydomain.com`)	chain-myauth@file	adminer_svc	docker	enabled
2	https://authelia.mydomain.com	authelia_rtr@docker	https	Host(`authelia.mydomain.com`)	chain-authelia@file	authelia_svc	docker	enabled
3	https://keycloak.mydomain.com	keycloak_rtr@docker	https	Host(`keycloak.mydomain.com`)	undefined	keycloak_svc	docker	enabled
4	https://portainer.mydomain.com	portainer_rtr@docker	https	Host(`portainer.mydomain.com`)	chain-authelia@file	portainer_svc	docker	enabled
5	https://myauth.mydomain.com	myauth_rtr@docker	https	Host(`myauth.mydomain.com`)	chain-myauth@file	myauth_svc	docker	enabled
6	https://whoami.mydomain.com	whoami_rtr@docker	https	Host(`whoami.mydomain.com`)	chain-myauth@file	whoami-docker	docker	enabled
````Preformatted text`


I have this middleware 

chain-no-auth:
  chain:
    middlewares:
      - middlewares-rate-limit
      - middlewares-https-redirectscheme
      - middlewares-secure-headers
      - middlewares-compress
chain-authelia:
  chain:
    middlewares:
      - middlewares-rate-limit
      - middlewares-https-redirectscheme
      - middlewares-secure-headers
      - middlewares-authelia
      - middlewares-compress
chain-myauth:
  chain:
    middlewares:
      - middlewares-rate-limit
      - middlewares-https-redirectscheme
      - middlewares-secure-headers
      - middlewares-myauth
      - middlewares-compress

middlewares-myauth:
  forwardAuth:
    address: "http://myauth:4181" # Make sure you have the myauth service in docker-compose.yml
    trustForwardHeader: true
    authResponseHeaders:
      - "X-Forwarded-User"
middlewares-authelia:
  forwardAuth:
    address: "http://authelia:9091/api/verify?rd=https://authelia.{{env "DOMAINNAME0"}}"
    trustForwardHeader: true
    authResponseHeaders:
      - "Remote-User"
      - "Remote-Groups"

		  
Traefik labels (docker-compose)

labels:
  - traefik.enable=true
  # HTTP-to-HTTPS Redirect
  - traefik.http.routers.http-catchall.entrypoints=http
  - traefik.http.routers.http-catchall.rule=HostRegexp(`{host:.+}`)
  - traefik.http.routers.http-catchall.middlewares=redirect-to-https
  - traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
  # HTTP Routers
  - traefik.http.routers.traefik_rtr.entrypoints=https
  - traefik.http.routers.traefik_rtr.rule=Host(`traefik.$DOMAINNAME0`)
  ## Services - API
  - traefik.http.routers.traefik_rtr.service=api@internal
  ## Middlewares
  - traefik.http.routers.traefik_rtr.middlewares=chain-no-auth@file
  # - traefik.http.routers.traefik_rtr.middlewares=chain-myauth@file 
  # - traefik.http.routers.traefik_rtr.middlewares=chain-authelia@file

  apache2:
    <<: *common-keys-core # See EXTENSION FIELDS at the top  
    container_name: apache2
    image: httpd:latest
    volumes:
      - ./website:/usr/local/apache2/htdocs
    labels:
      - traefik.enable=true
      ## HTTP Routers
      - traefik.http.routers.Apache2_rtr.entrypoints=https
      - traefik.http.routers.Apache2_rtr.rule=Host(`apache.$DOMAINNAME0`)
      ## Middlewares
      - traefik.http.routers.Apache2_rtr.middlewares=chain-no-auth@file
      # - traefik.http.routers.Apache2_rtr.middlewares=chain-myauth@file
      # - traefik.http.routers.Apache2_rtr.middlewares=chain-authelia@file
      ## HTTP Services
      - traefik.http.routers.Apache2_rtr.service=Apache2_svc
      - traefik.http.services.Apache2_svc.loadbalancer.server.port=80

I have put several middleware in traefik service and apache2 and comment/uncomment for testing purpose
I think the problem comes from traefik middleware with authentication :
if chain-no-auth@file then everything is ok
if chain-authelia@file then https://apache.mydomain.com/ do not work, but https://apache.mydomain.com/test.html is ok

firefox debug windows

Uncaught SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data onload https://apache.mydomain.com/script.js:5

if chain-myauth@file then https://apache.mydomain.com/ do not work, but https://apache.mydomain.com/test.html is ok

firefox debug windows:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://keycloak.mydomain.com/auth/realms/r4my/protocol/openid-connect/auth?client_id=myauth&redirect_uri=https%3A%2F%2Fmyauth.mydomain.com%2F_oauth&response_type=code&scope=profile+email&state=2e0f906e4c7a08a9499a09a6f336528b%3Ageneric-oauth%3Ahttps%3A%2F%2Ftraefik.mydomain.com%2Fapi%2Fhttp%2Frouters. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.

I was first looking to solve CORS problem because the last error is saying : (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
But in fact if I swith to authelia authentication then I have a different problem.
Also with the test.html which is not requested traefik api back this works without problem

I hope that can help

1 Like