diff --git a/pygitweb/auth_test.py b/pygitweb/auth_test.py
index eb182bc..b733b04 100644
--- a/pygitweb/auth_test.py
+++ b/pygitweb/auth_test.py
@@ -69,3 +69,35 @@ def test_login_form_sets_cookie_and_users_me(client: TestClient) -> None:
 		r2 = client.get("/users/me")
 		assert r2.status_code == 200
 		assert r2.json()["username"] == "admin"
+
+
+def test_projectnamevalid_no_auth_required_when_auth_disabled(client: TestClient) -> None:
+	with patch.object(settings, "AUTH", False), patch("pygitweb.main.project_visible_in_list", return_value=False):
+		r = client.get("/projectnamevalid", params={"name": "newproj"})
+	assert r.status_code == 200
+
+
+def test_projectnamevalid_401_without_credentials_when_auth_enabled(client: TestClient) -> None:
+	with (
+		patch.object(settings, "AUTH", True),
+		patch.object(settings, "ADMIN_USER", "admin"),
+		patch.object(settings, "ADMIN_PASSWORD", "secret"),
+	):
+		r = client.get("/projectnamevalid", params={"name": "newproj"})
+	assert r.status_code == 401
+
+
+def test_projectnamevalid_ok_with_bearer_when_auth_enabled(client: TestClient) -> None:
+	with (
+		patch.object(settings, "AUTH", True),
+		patch.object(settings, "ADMIN_USER", "admin"),
+		patch.object(settings, "ADMIN_PASSWORD", "secret"),
+		patch("pygitweb.main.project_visible_in_list", return_value=False),
+	):
+		tok = client.post("/token", data={"username": "admin", "password": "secret"}).json()["access_token"]
+		r = client.get(
+			"/projectnamevalid",
+			params={"name": "newproj"},
+			headers={"Authorization": f"Bearer {tok}"},
+		)
+	assert r.status_code == 200
diff --git a/pygitweb/main.py b/pygitweb/main.py
index 395040e..b900b38 100644
--- a/pygitweb/main.py
+++ b/pygitweb/main.py
@@ -57,7 +57,9 @@ from pygitweb.api.subpage import Subpage
 from pygitweb.auth import (
 	access_token_from_request,
 	auth_router,
+	decode_access_token,
 	ensure_active_user_if_auth_enabled,
+	get_auth_credentials,
 	require_active_user_if_auth_enabled,
 )
 from pygitweb.change_queue import CHANGE_QUEUE
@@ -427,8 +429,11 @@ _OPTIONAL_REPO_ZIP = File(default=None)
 
 
 @app.get("/projectnamevalid", response_class=HTMLResponse)
-def addproject_namevalid(name: Annotated[str | None, Query()] = None):
-	"""Check if project name is valid."""
+def addproject_namevalid(
+	_: Annotated[None, Depends(require_active_user_if_auth_enabled)],
+	name: Annotated[str | None, Query()] = None,
+):
+	"""Check if project name is valid (authenticated when PYGITWEB auth is enabled)."""
 	if not name:
 		raise HTTPException(status_code=400, detail="Param 'name' required")
 	if not is_valid_pathname(name):
@@ -439,8 +444,13 @@ def addproject_namevalid(name: Annotated[str | None, Query()] = None):
 
 
 @app.get("/addproject", response_class=HTMLResponse)
-def addproject_page(request: Request):
+def addproject_page(
+	token: Annotated[str | None, Depends(access_token_from_request)],
+):
 	"""Add project form page."""
+	show_sign_in_notice = (
+		settings.AUTH and get_auth_credentials() is not None and (not token or decode_access_token(token) is None)
+	)
 	pre = PREAMBLE.render(
 		title=f"{settings.SITE_NAME} - Add Project",
 		site_name=settings.SITE_NAME,
@@ -448,6 +458,7 @@ def addproject_page(request: Request):
 	tpl = env.get_template("addproject.html")
 	body = tpl.render(
 		site_name=settings.SITE_NAME,
+		show_sign_in_notice=show_sign_in_notice,
 		empty_repo_form_content=Project.form_content(),
 		upload_zip_form_content=ProjectZip.form_content(),
 	)
diff --git a/pygitweb/settings.py b/pygitweb/settings.py
index 4978964..9c1b5ab 100644
--- a/pygitweb/settings.py
+++ b/pygitweb/settings.py
@@ -11,9 +11,10 @@ from typing import Any
 from urllib.parse import quote
 
 import pygit2
-from fastapi import APIRouter, Request
+from fastapi import APIRouter, Depends, Request
 from fastapi.responses import HTMLResponse, RedirectResponse
 
+from pygitweb.auth import require_active_user_if_auth_enabled
 from pygitweb.config import settings
 from pygitweb.dependencies import ValidatedSettingsProject
 from pygitweb.templates_env import POSTAMBLE, PREAMBLE, env, jinja_escape
@@ -28,7 +29,11 @@ def _quote_path(path: str) -> str:
 GIT_CONFIG_LEVEL_LOCAL = 5
 GIT_CONFIG_LEVEL_WORKTREE = 6
 
-router = APIRouter(prefix="/settings", tags=["settings"])
+router = APIRouter(
+	prefix="/settings",
+	tags=["settings"],
+	dependencies=[Depends(require_active_user_if_auth_enabled)],
+)
 
 
 # ---------- PyGitWeb settings schema ----------
diff --git a/pygitweb/templates/addproject.html b/pygitweb/templates/addproject.html
index 34752bc..c3d5183 100644
--- a/pygitweb/templates/addproject.html
+++ b/pygitweb/templates/addproject.html
@@ -1,4 +1,9 @@
 <h1 class="page-title">Add project</h1>
+{% if show_sign_in_notice %}
+<div class="alert board-task-error-hint py-2 px-3 mb-3" role="alert">
+  You must be signed in to add a project (sign in via the sidebar or <a href="/login?next=/addproject">open the sign-in page</a>).
+</div>
+{% endif %}
 <div class="card">
   <div class="card-body">
     <form action="/addproject" method="post" enctype="multipart/form-data" class="needs-validation" novalidate>
@@ -73,8 +78,9 @@
       return;
     }
     var url = '/projectnamevalid?name=' + encodeURIComponent(name);
-    fetch(url)
+    fetch(url, { credentials: 'same-origin' })
       .then(function(res) {
+        // 401/403 when not logged in → red outline; same as other validation failures.
         setProjectNameBorder(res.ok);
       })
       .catch(function() {
