In this article you are going to learn how to authorize requests in Caddy using forward_auth directive.
Below is what you are trying to achieve.
There is an auth server that authenticates requests, and there is a resource server that returns the requested resource.
You want each request to get authenticated by the auth server and get to the resource server only if successfully authenticated.

Mock Auth Server #
I am going to provide you with a very simple auth server written in Go, you are free to rewrite this in any language you want. Its very simple.
package main import ( "fmt" "net/http" ) func main() { fmt.Println("Starting server on port 8880") http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Authorization") == "" { w.WriteHeader(http.StatusForbidden) return } w.WriteHeader(http.StatusOK) w.Write([]byte("Authorized!")) }) http.ListenAndServe(":8880", nil) }main.go
Here is what the server does (implement this in any other language you want).
- Starts on port
8880. - If the request has any value in
Authorizationheader, returns status200. - If the request does not have any value in
Authorizationheader, returns status403.
(Reason for these status codes explained later)
You can run this program by doing
go run main.go
Caddyfile #
Write a simple Caddyfile that returns a value on the route /resource.
:8080 {
handle /resource {
respond "Resource X"
}
}
The above Caddyfile starts listening on port 8080 and returns Resource X on pathg /resource.
Run the caddy server by doing.
caddy run --config Caddyfile
(You can also run Caddy using Docker)
Send a request to localhost:8080 you should get a response.
curl -i "localhost:8080/resource"
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Server: Caddy
Date: Sun, 09 Jul 2023 21:59:47 GMT
Content-Length: 10
Resource X%
Protecting with forward_auth #
You want to protect /resource endpoint and only allow authenticated requests to access it.
Use the forward_auth directive to send a request to the auth server running on port 8880 in order to authenticate the current request.
:8080 {
handle /resource {
forward_auth localhost:8880 {
uri /
}
respond "Resource X"
}
}
This is how the above works.
forward_authsends a copy of each request to auth server running onlocalhost:8880at path/.- If the auth server returns a response with status
2XXcaddy continues with the request. - If the auth sever returns a non-
2XXstatus code, the non-2XXresponse is sent back the client.
Make a request with no Authorization header.
curl -i "localhost:8080/resource"
HTTP/1.1 403 Forbidden
Content-Length: 0
Date: Sun, 09 Jul 2023 22:07:40 GMT
Server: Caddy
Make a request with a Authorization header.
curl -i "localhost:8080/resource" --header 'Authorization: any-value'
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Server: Caddy
Date: Sun, 09 Jul 2023 22:07:56 GMT
Content-Length: 10
Resource X%
Under the hood, forward_auth uses reverse_proxy directive, read the explanation in Caddy docs here.
Below is a more detailed, complicated looking diagram showing the flow of forward_auth.





