Cant get POST method with basicauth to be authorized

1. The problem I’m having:

I have a (flask) server and was trying to implement basic authentification for some resources using caddy.

For now, I’m just trying to make it work locally.

Im using Caddy-Docker-Proxy to generate the Caddyfile from docker labels.

The route I’m having problems with is /app/test/
It is a POST request that Im trying to send from the frontend (browser). Precising browser because it works from postman, since it doesnt need preflight.

It send a preflight OPTIONS request :

curl "http://localhost:8008/app/test" -X \
 OPTIONS -H \
 "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0" -H \
 "Accept: */*" -H \
 "Accept-Language: en-CA,en-US;q=0.7,en;q=0.3" -H \
 "Accept-Encoding: gzip, deflate, br" -H \
 "Access-Control-Request-Method: POST" -H \
 "Access-Control-Request-Headers: authorization,content-type" -H \
 "Referer: http://localhost:8080/" -H \
 "Origin: http://localhost:8080" -H \
 "Connection: keep-alive" -H \
 "Sec-Fetch-Dest: empty" -H \
 "Sec-Fetch-Mode: cors" -H \
 "Sec-Fetch-Site: same-site"

then this POST request :

curl "http://localhost:8008/app/test" -X \
 POST -H \
 "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0" -H \
 "Accept: application/json, text/plain, */*" -H \
 "Accept-Language: en-CA,en-US;q=0.7,en;q=0.3" -H \
 "Accept-Encoding: gzip, deflate, br" -H \
 "Content-Type: application/json;charset=utf-8" -H \
 "Authorization: Basic YWRtaW46aGFzaA==" -H \
 "Content-Length: 6237" -H \
 "Origin: http://localhost:8080" -H \
 "Connection: keep-alive" -H \
 "Referer: http://localhost:8080/" -H \
 "Sec-Fetch-Dest: empty" -H \
 "Sec-Fetch-Mode: cors" -H \
 "Sec-Fetch-Site: same-site"

I tried running it using cors-anywhere while running my server through ngrok and was able to make it work.

curl "https://cors-anywhere.herokuapp.com/http://<ngrok-sub-domain>.ngrok-free.app/app/test" -X \
 OPTIONS -H \
 "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0" -H \
 "Accept: */*" -H \
 "Accept-Language: en-CA,en-US;q=0.7,en;q=0.3" -H \
 "Accept-Encoding: gzip, deflate, br" -H \
 "Access-Control-Request-Method: POST" -H \
 "Access-Control-Request-Headers: authorization,content-type" -H \
 "Referer: http://localhost:8080/" -H \
 "Origin: http://localhost:8080" -H \
 "Connection: keep-alive" -H \
 "Sec-Fetch-Dest: empty" -H \
 "Sec-Fetch-Mode: cors" -H \
 "Sec-Fetch-Site: cross-site"

My question is can I set up Caddy to accept my resquest and how?

2. Error messages and/or full log output:

response headers from the OPTIONS request :

HTTP/1.1 401 Unauthorized
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: authorization,content-type
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: access-control-allow-origin,access-control-allow-methods,access-control-allow-headers
Connection: keep-alive
Server: Caddy
Www-Authenticate: Basic realm="restricted"
Date: Thu, 27 Apr 2023 20:04:48 GMT
Content-Length: 0

and from the OPTIONS request using cors-anywhere, which worked:

HTTP/1.1 200 OK
Server: Cowboy
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: authorization,content-type
Access-Control-Expose-Headers: access-control-allow-origin,access-control-allow-methods,access-control-allow-headers
Date: Thu, 27 Apr 2023 19:09:54 GMT
Transfer-Encoding: chunked
Via: 1.1 vegur

I see that the Access-Control-Allow-Methods Header doesnt appear in the Unauthorized version. But i added it in my caddy config.

3. Caddy version:

v2.6.4

4. How I installed and ran Caddy:

a. System environment:

Docker

b. Command:

docker compose -f docker-compose.yaml up

c. Service/unit/compose file:

docker-compose.yaml :

version: '3.9'
services:
  caddy:
    image: lucaslorentz/caddy-docker-proxy:ci-alpine
    ports:
      - 80:80
      - 443:443
      - 8008:8008
    environment:
      - CADDY_INGRESS_NETWORKS=caddy #listen to caddy network
    networks:
      - caddy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock #access docker daemon 
      - caddy_data:/data #store caddy data
    restart: unless-stopped
  server:
    container_name: dev-server
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./data:/data/
      - .:/app/
    networks:
      - caddy
    env_file:
      - .env
    entrypoint: ["gunicorn", "--reload", "main:app", "-c", "gunicorn.conf.py"]
    environment:
      - PORT=8008  
    labels:
      caddy: :8008
      caddy.route_0: /app/*
      caddy.route_0.reverse_proxy: server:8008

      caddy.route_1: /app/test
      caddy.route_1.basicauth.admin: hash
      caddy.header: /app/test
      caddy.header.Access-Control-Allow-Origin: "*"
      caddy.header.Access-Control-Allow-Methods: 'GET, POST, PUT, DELETE, OPTIONS'
      caddy.header.Access-Control-Allow-Headers: 'authorization,content-type'
      caddy.header.Access-Control-Expose-Headers: 'access-control-allow-origin,access-control-allow-methods,access-control-allow-headers'
      caddy.header.Access-Control-Allow-Credentials: true
      caddy.header.Connection: keep-alive
volumes:
  caddy_data: {}
networks:
  caddy:
    external: true

d. My complete Caddy config:

The caddyfile is generated from labels in docker-compose file but here’s what the logs give me (once formatted) :

:8008 {
	header /app/test {
		Access-Control-Allow-Credentials true
		Access-Control-Allow-Headers authorization,content-type
		Access-Control-Allow-Methods GET, POST, PUT, DELETE, OPTIONS
		Access-Control-Allow-Origin *
		Access-Control-Expose-Headers access-control-allow-origin,access-control-allow-methods,access-control-allow-headers
		Connection keep-alive
	}
	route /app/* {
		reverse_proxy server:8008
	}
	route /app/test {
		basicauth {
			admin hash
		}
	}
}

as you can see, I added response header to my protected route; they all appear, except for Access-Control-Allow-Methods.

5. Links to relevant resources:

Caddy Docker Proxy

cors-anywhere

You could skip basicauth for OPTIONS like this:

@not-options not method OPTIONS
basicauth @not-options {
	...
}
1 Like

Thanks for the quick reply! It worked!

Here’s my final config if ever it can help someone else.

:8008 {
	@not-options not method OPTIONS
	route /app/* {
		reverse_proxy server:8008
	}
	route /app/test {
		basicauth @not-options {
			admin hash
		}
	}
}

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.