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
Authorization
header, returns status200
. - If the request does not have any value in
Authorization
header, 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_auth
sends a copy of each request to auth server running onlocalhost:8880
at path/
.- If the auth server returns a response with status
2XX
caddy continues with the request. - If the auth sever returns a non-
2XX
status code, the non-2XX
response 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
.