a project


An opinionated directive which proxies a clone of the request to an authentication gateway, which can decide whether handling should continue, or needs to be sent to a login page.

Caddy's reverse_proxy is capable of performing "pre-check requests" to an external service, but this directive is tailored specifically for the authentication usecase. This directive is actually just a convenient way to use a longer, more common configuration (below).

This directive makes a GET request to the configured upstream with the uri rewritten:

  • If the upstream responds with a 2xx status code, then access is granted and the header fields in copy_headers are copied to the original request, and handling continues.
  • Otherwise, if the upstream responds with any other status code, then the upstream's response is copied back to the client. This response should typically involve a redirect to login page of the authentication gateway.

If this behaviour is not exactly what you want, you may take the expanded form below as a basis and customize it to your needs.

All the subdirectives of reverse_proxy are supported, and passed through to the underlying reverse_proxy handler.


forward_auth [<matcher>] [<upstreams...>] {
	uri          <to>
	copy_headers <fields...> {
  • <upstreams...> is a list of upstreams (backends) to which to send auth requests.

  • uri is the URI (path and query) to set on the request sent to the upstream. This will usually be the verification endpoint of the authentication gateway.

  • copy_headers is a list of HTTP header fields to copy from the response to the original request, when the request has a success status code.

    The field can be renamed by using > followed by the new name, for example Before>After.

    A block may be used to list all the fields, one per line, if you prefer for readability.

Since this directive is an opinionated wrapper over a reverse proxy, you can use any of reverse_proxy's subdirectives to customize it.

Expanded form

The forward_auth directive is the same as the following configuration. Auth gateways like Authelia work well with this preset. If yours does not, feel free to borrow from this and customize it as needed instead of using the forward_auth shortcut.

reverse_proxy <upstreams...> {
	# Always GET, so that the incoming
	# request's body is not consumed
	method GET

	# Change the URI to the auth gateway's
	# verification endpoint
	rewrite <to>

	# Forward the original method and URI,
	# since they get rewritten above; this
	# is in addition to other X-Forwarded-*
	# headers already set by reverse_proxy
	header_up X-Forwarded-Method {method}
	header_up X-Forwarded-Uri {uri}

	# On a successful response, copy response headers
	@good status 2xx
	handle_response @good {
		request_header {
			# for example, for each copy_headers field...
			Remote-User {rp.header.Remote-User}
			Remote-Email {rp.header.Remote-Email}



Delegating authentication to Authelia, before serving your app via a reverse proxy:

# Serve the authentication gateway itself {
	reverse_proxy authelia:9091

# Serve your app {
	forward_auth authelia:9091 {
		uri /api/verify?rd=
		copy_headers Remote-User Remote-Groups Remote-Name Remote-Email

	reverse_proxy app1:8080

For more information, see Authelia's documentation for integrating with Caddy.


Delegating authentication to Tailscale (currently named nginx-auth, but it still works with Caddy), and using the alternative syntax for copy_headers to rename the copied headers (note the > in each header):

forward_auth unix//run/tailscale.nginx-auth.sock {
	uri /auth
	header_up Remote-Addr {remote_host}
	header_up Remote-Port {remote_port}
	header_up Original-URI {uri}
	copy_headers {