git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] http.c: prompt for username on 403

From
Ashlesh Gawande <git@ashlesh.me>
Date
Oct 14, 2025, 14:43 UTC
Message-ID
<20251014144354.1457818-2-git@ashlesh.me>
Scenario:
- There are a few pre-production systems that a lot of testers and
  developers need to time share because of low availability
- Devops generates a GitHub token with pull only access
  and adds it to the netrc file on these systems
  (Pull only as we don't want testers/others to be able to push)
- Testers log in and do a git pull for the latest changes
  (via netrc credentials - though testers may not be aware)
- Developers login to debug issues and may make fixes to the test repo
- Now when developers try to push their changes they receive:
  fatal: unable to access 'https://github.com/<org>/<project>/':
  The requested URL returned error: 403
- The developer is not given the chance to supply an authorized token
  and either needs to comment the netrc file or copy the changes over
  to their own machine
Signed-off-by: Ashlesh Gawande <git@ashlesh.me>
---
 http.c                     |  2 +-
 t/lib-httpd.sh             |  9 +++++++++
 t/lib-httpd/apache.conf    |  4 ++++
 t/lib-httpd/passwd         |  1 +
 t/t5550-http-fetch-dumb.sh | 24 ++++++++++++++++++++++++
 5 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/http.c b/http.c
index 7e3af1e72f..18959f63b9 100644
--- a/http.c
+++ b/http.c
@@ -1852,7 +1852,7 @@ static int handle_curl_result(struct slot_results *results)
 		return HTTP_NOMATCHPUBLICKEY;
 	} else if (missing_target(results))
 		return HTTP_MISSING_TARGET;
-	else if (results->http_code == 401) {
+	else if (results->http_code == 401 || results->http_code == 403) {
 		if ((http_auth.username && http_auth.password) ||\
 		    (http_auth.authtype && http_auth.credential)) {
 			if (http_auth.multistage) {
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 5091db949b..cdc92b2916 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -325,6 +325,15 @@ set_askpass() {
 	echo "$2" >"$TRASH_DIRECTORY/askpass-pass"
 }
 
+set_netrc() {
+	# $HOME=$TRASH_DIRECTORY
+	echo "machine $1 login $2 password $3" > $TRASH_DIRECTORY/.netrc
+}
+
+clear_netrc() {
+	rm "$TRASH_DIRECTORY/.netrc"
+}
+
 expect_askpass() {
 	dest=$HTTPD_DEST${3+/$3}
 
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index e631ab0eb5..6b8c50a51a 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -238,6 +238,10 @@ SSLEngine On
 	AuthName "git-auth"
 	AuthUserFile passwd
 	Require valid-user
+
+	# return 403 for authenticated user: forbidden-user@host
+	RewriteCond "%{REMOTE_USER}" "^forbidden-user@host"
+	RewriteRule ^ - [F]
 </Location>
 
 <LocationMatch "^/auth-push/.*/git-receive-pack$">
diff --git a/t/lib-httpd/passwd b/t/lib-httpd/passwd
index d9c122f348..3bab7b6423 100644
--- a/t/lib-httpd/passwd
+++ b/t/lib-httpd/passwd
@@ -1 +1,2 @@
 user@host:$apr1$LGPmCZWj$9vxEwj5Z5GzQLBMxp3mCx1
+forbidden-user@host:$apr1$LGPmCZWj$9vxEwj5Z5GzQLBMxp3mCx1
diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh
index ed0ad66fad..6c4c1cafb2 100755
--- a/t/t5550-http-fetch-dumb.sh
+++ b/t/t5550-http-fetch-dumb.sh
@@ -102,6 +102,30 @@ test_expect_success 'cloning password-protected repository can fail' '
 	expect_askpass both wrong
 '
 
+test_expect_success 'using credentials from netrc to clone successfully' '
+	set_askpass wrong &&
+	set_netrc 127.0.0.1 user@host pass@host &&
+	git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-netrc &&
+	expect_askpass none
+'
+clear_netrc
+
+test_expect_success 'netrc unauthorized credentials (prompt after 401)' '
+	set_askpass wrong &&
+	set_netrc 127.0.0.1 user@host pass@wrong &&
+	test_must_fail git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-netrc-401 &&
+	expect_askpass both wrong
+'
+clear_netrc
+
+test_expect_success 'netrc authorized but forbidden credentials (prompt after 403)' '
+	set_askpass wrong &&
+	set_netrc 127.0.0.1 forbidden-user@host pass@host &&
+	test_must_fail git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-netc-403 &&
+	expect_askpass both wrong
+'
+clear_netrc
+
 test_expect_success 'http auth can use user/pass in URL' '
 	set_askpass wrong &&
 	git clone "$HTTPD_URL_USER_PASS/auth/dumb/repo.git" clone-auth-none &&
-- 
2.43.0
Next: brian m. carlson
Message 1 of 11 in “http.c: prompt for username on 403”
  1. http.c: prompt for username on 403Ashlesh Gawande, Oct 14, 2025
  2. brian m. carlsonOct 14, 2025
  3. Ashlesh GawandeOct 15, 2025
  4. brian m. carlsonOct 15, 2025
  5. Ashlesh GawandeDec 9, 2025
  6. brian m. carlsonDec 10, 2025
  7. Ashlesh GawandeDec 10, 2025
  8. rsbecker@nexbridge.comDec 10, 2025
  9. brian m. carlsonDec 10, 2025
  10. Ashlesh GawandeDec 11, 2025
  11. Ashlesh GawandeDec 10, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.