Skip to content

fix(nginx): przepuść /.well-known/ (discovery OAuth) mimo blokady plików ukrytych#21

Merged
mpasternak merged 1 commit into
mainfrom
fix-well-known-oauth-discovery
Jul 22, 2026
Merged

fix(nginx): przepuść /.well-known/ (discovery OAuth) mimo blokady plików ukrytych#21
mpasternak merged 1 commit into
mainfrom
fix-well-known-oauth-discovery

Conversation

@mpasternak

Copy link
Copy Markdown
Member

Problem

GET https://<host>/.well-known/oauth-authorization-server zwracał 403 od
nginksa
na każdym wdrożeniu — mimo że serwer autoryzacji OAuth działał bez
zarzutu:

Endpoint Status
/o/authorize/ 302 → /accounts/login/
/o/token/ 400 (czeka na parametry) ✅
/o/register/ (DCR) 201, poprawny client_id
/.well-known/oauth-authorization-server 403 nginx

Skutkiem było to, że klient MCP (bpp-mcp)
nie mógł wykonać discovery (RFC 8414) i logowanie padało na pierwszym kroku,
choć całe OAuth było gotowe do użycia.

Przyczyna

_bpp-locations.conf blokuje pliki ukryte:

location ~ /\. {
    deny all;
}

To regex, a regexy w nginksie mają pierwszeństwo przed zwykłymi prefiksami.
/.well-known/ zaczyna się od kropki, więc wpadał w tę regułę i żaden
prefiksowy location nie mógł go wyprzedzić.

Diagnoza potwierdzona z zewnątrz: losowa ścieżka pod /.well-known/ też
dawała 403 (a nie 404), co dowodzi, że blokuje nginx, a nie Django.

Naprawa

location ^~ /.well-known/ {
    limit_req zone=bpp_general burst=100 nodelay;
    try_files $uri @proxy_to_app;
}

Modyfikator ^~ stawia prefiks ponad regexami. /.well-known/ (RFC 8615)
to standardowa przestrzeń metadanych serwisu, a nie „plik ukryty" — leżą tam
metadane OAuth i security.txt. Django odpowiada 404 na nieznane ścieżki, więc
nic się nie odsłania, a .git/.env dalej łapie regex poniżej.

ACME nie był dotknięty

Sprawdzone osobno: po HTTP (port 80) /.well-known/acme-challenge/ zwraca 404,
nie 403. Blok port-80 w vhost.conf.template nie includuje
_bpp-locations.conf, więc reguła tam nie sięgała i walidacja Let's Encrypt
działała przez cały czas.

Test

Nowy blok 15d w istniejącym harnessie test_nginx_runtime — startuje
prawdziwy nginx:1.30.2 z pełnym łańcuchem entrypointów i fake appserverem,
po czym sprawdza obie strony kontraktu naraz:

  • /.well-known/oauth-authorization-server musi dojść do appservera
    (asercja na echo ścieżki, nie na samo 200),
  • /.git/config i /.env muszą dalej dostawać 403.

Druga asercja jest tu kluczowa: bez niej „naprawa" polegająca na skasowaniu
blokady plików ukrytych przechodziłaby jako zielona.

Weryfikacja:

  • przed poprawką 15d pada (403 zamiast proxy),
  • po poprawce 22/22 zielone,
  • testy ACME (15c) bez zmian.

Uwaga wdrożeniowa

Do czasu wdrożenia tej zmiany bpp-mcp radzi sobie fallbackiem na /o/*
(bpp-mcp#…), ale to obejście po stronie
klienta. Natywny przycisk „authorize" w Claude (tryb HTTP) wymaga tej
poprawki
— tam discovery robi sam klient Claude i fallbacku nie ma.

…kow ukrytych

Reguła `location ~ /\.` blokujaca .git/.env przechwytywala takze
/.well-known/ i zwracala 403. Regexy w nginksie maja pierwszenstwo przed
zwyklymi prefiksami, wiec zaden prefiksowy location nie mogl jej wyprzedzic.

Skutek: metadane serwera autoryzacji OAuth (RFC 8414,
/.well-known/oauth-authorization-server) byly nieosiagalne z zewnatrz.
Klient MCP `bpp-mcp` nie mogl przeprowadzic discovery i logowanie padalo,
mimo ze /o/authorize/, /o/token/ i /o/register/ dzialaly poprawnie.

Naprawa: `location ^~ /.well-known/` — modyfikator `^~` stawia prefiks
ponad regexami. Django odpowiada 404 na nieznane sciezki .well-known,
wiec nic sie nie odslania, a .git/.env dalej lapie regex.

ACME (Let's Encrypt) nie byl dotkniety: blok port-80 w vhost.conf.template
nie includuje _bpp-locations.conf, wiec walidacja HTTP-01 dzialala.

Test 15d w tests/test_makefile.sh pilnuje obu stron kontraktu naraz:
/.well-known/oauth-authorization-server musi dojsc do appservera, a
/.git/config i /.env musza dalej dostawac 403 — zeby "naprawa" polegajaca
na skasowaniu blokady plikow ukrytych nie przeszla jako zielona.

Zweryfikowane na nginx:1.30.2: przed poprawka 15d pada (403), po
poprawce 22/22 zielone, testy ACME bez zmian.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019D6Zytbsj8xjZCx8etyMeN
@mpasternak
mpasternak merged commit d751360 into main Jul 22, 2026
5 checks passed
@mpasternak
mpasternak deleted the fix-well-known-oauth-discovery branch July 22, 2026 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant