Forward_auth Redirect not Working

1. The problem I’m having:

I want to use Caddy’s forward_auth such that when I visit lab.domain.dev it goes to auth.domain.dev and after succesful login goes back to lab.domain.dev

However, currently I only get the first redirect, aka from lab.domain.dev to auth.domain.dev, after a successful login I get the default authelia logged in screen at https://auth.domain.dev/authenticated

Other aspects of the login flow work properly, i.e. if I manually visit my page after logging in, it works as it should. I can also see the authelia cookie being set properly, etc etc.

I’ve been searching various combinations of authelia, caddy, authelia and caddy but I can’t find anything that helps with this case. I found some similar entries such as: Authelia redirects to itself / forward_auth - #2 by francislavoie
But it is not the exact same issue nor was I able to fix it from the info there.

Also I have noticed that any command that uses header_up that I found during my searches essentially does nothing. I have inspected the headers in my requests but they are absolutely unaffected by header_up, i.e. the Host header I currently have in my Caddyfile does not show up, nor does any other header that is not “default”. I guess the minimum amount of needed headers for a request/response to work.

I mean in essence it makes sense why the redirect doesn’t happen, there is no way for the page to know how to get back, when the information is not set anywhere. But I really can’t find how to set it.

2. Error messages and/or full log output:

No relevant logs as there is no visible error. The functionality is simply missing.

3. Caddy version:

v2.7.4

4. How I installed and ran Caddy:

a. System environment:

Docker

b. Command:

docker compose up

c. Service/unit/compose file:

version: '3.8'

services:

  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    restart: 'unless-stopped'
    ports:
      - 8096:8096
      - 8920:8920
    volumes:
      - ./jellyfin/config:/config
      - ./jellyfin/cache:/cache
      - ./jellyfin/media:/media
      - ./jellyfin/media2:/media2:ro
    networks:
      - lab-network

  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - 1336:1336
      - 1337:1337
      - 1337:1337/udp
    volumes:
      - ./caddy/Caddyfile:/etc/caddy/Caddyfile
      - ./caddy/site:/srv
      - ./caddy/data:/data
      - ./caddy/config:/config
    networks:
      - lab-network

  authelia:
    image: authelia/authelia:latest
    container_name: authelia
    restart: unless-stopped
    depends_on:
      - postgres
      - redis
    volumes:
      - ./authelia/config:/config
    environment:
      TZ: Europe/Copenhagen
      AUTHELIA_JWT_SECRET_FILE: /config/secrets/JWT_SECRET
      AUTHELIA_SESSION_SECRET_FILE: /config/secrets/SESSION_SECRET
      AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE: /config/secrets/SMTP_PASSWORD
      AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE: /config/secrets/STORAGE_ENCRYPTION_KEY
      AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE: /config/secrets/STORAGE_PASSWORD
      AUTHELIA_SESSION_REDIS_PASSWORD_FILE: /config/secrets/REDIS_PASSWORD
    networks:
      - lab-network

  postgres:
    image: postgres:15
    container_name: postgres
    restart: unless-stopped
    volumes:
      - ./postgres:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: "authelia"
      POSTGRES_PASSWORD: "redacted"
    networks:
      - lab-network

  redis:
    image: redis:7
    container_name: redis
    restart: unless-stopped
    command: "redis-server --save 60 1 --loglevel warning --requirepass [redacted]"
    volumes:
      - ./redis:/data
    networks:
      - lab-network

networks:
  lab-network:
    driver: bridge

d. My complete Caddy config:

{
    http_port 1336
    https_port 1337
}

(secure) {
  forward_auth {args[0]} https://auth.domain.dev {
    uri /api/verify?rd=https://auth.domain.dev
    copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
    header_up Host {upstream_hostport}
  }
}

auth.domain.dev {
    reverse_proxy authelia:9091
}

lab.domain.dev {
    import secure *
    redir /tv /tv/
    reverse_proxy /tv/* jellyfin:8096
}

5. Links to relevant resources:

I followed this guide for setting up caddy and authelia: Securing web apps with Caddy and Authelia in Docker Compose: an opinionated, practical, and minimal production-ready login portal guide

I don’t use authelia myself but if I remember correctly rd is meant to be the redirect target after being authenticated. So I think that should be your labs domain.

Double check with the authelia docs, it should clarify.

That was one of my initial ideas as well, however when I try to change it to i.e. lab url as so:

{
    http_port 1336
    https_port 1337
}

(secure) {
  forward_auth {args[0]} https://auth.domain.dev {
    uri /api/verify?rd=https://lab.domain.dev
    copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
    header_up Host {upstream_hostport}
  }
}

auth.domain.dev {
    reverse_proxy authelia:9091
}

lab.domain.dev {
    import secure *
    redir /tv /tv/
    reverse_proxy /tv/* jellyfin:8096
}

It results in behavior where it infinitely appends the auth (yes auth surprisingly) url to the calls as so:

Call 1:

https://lab.domain.dev/?rd=https%3A%2F%2Fauth.domain.dev%3A443%2F&rm=GET

Call 2:

https://lab.domain.dev/?rd=https%3A%2F%2Fauth.domain.dev%3A443%2F%3Frd%3Dhttps%253A%252F%252Fauth.domain.dev%253A443%252F%26rm%3DGET&rm=GE

And continues to do this in an infinite loop of calls until it results in:

431 Request Header Fields Too Large

On a similar note, even setting the default_redirection_url in authelia config file, which according to authelia docs should only kick in if you don’t have a target url: Miscellaneous - Configuration - Authelia

does not result in redirecting to lab.domain.dev, instead it gives me the standard: https://auth.domain.dev/authenticated

   uri /api/verify?rd=https://lab.domain.dev

Needs to be:

   uri /api/verify?rd=https://auth.domain.dev

You’re instructing Authelia to redirect the user to https://lab.domain.dev if they’re not authenticated when checked. Resulting in the loop.

If I had my eyes on Francis wouldn’t have had to highlight I missed something. Sorry for rushing my reply.

The original issue is usually indicative of use of the http:// scheme on the endpoint. Would you happen to be willing to upload a HAR file for us to look at? Please pay close attention to the security sensitive information elements: HTTP Archive Files - Reference - Authelia

You should carefully anonymize the cookie/set-cookie header values so they are not the same as what was in the response/request. You can make adjustments to the domain to anonymize it, and you can remove the username, password, and 2FA credentials from the request as long as you don’t break the JSON data.

If you’re more comfortable there are contact methods on my GitHub profile.

1 Like

One other element I noticed. Authelia relies on the X-Forwarded-* headers being accurate for the original request. If you set the forward_auth endpoint to https://auth.example.com Caddy may inadvertently change those before the request makes it to /api/verify. Meaning the request isn’t accurate to the original request, but accurate to the request made to the /api/verify endpoint itself (which is not useful in this situation). It is generally recommended to directly send the request if possible to the http port of Authelia. If you can’t do that ensuring the /api/verify and anything starting with /api/authz/ has Caddy skipping altering those headers, if that’s possible.

However Caddy may automatically do this in this situation since the origin of the request is Caddy itself.

2 Likes

Thanks James, makes sense.

So basically make sure to change this to authelia:9091 instead of https://auth.domain.dev

Thanks to both of you, the help is very much appreciated. I have actually figured out the issue in the mean time as well, or rather the fix with changing https://auth.domain.dev to authelia:9091.

But I wasn’t 100% sure why it is happening so the extra context is helpful :slight_smile:

So everything works now!

2 Likes

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