{"thread":{"id":"63712","subject":"Failing to push to a repository erases authentication helper credentials","startedAt":"2025-06-30T13:45:33Z","lastAt":"2025-07-03T10:44:38Z","messageCount":8,"participants":["Michal Suchánek","brian m. carlson","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"520916","messageId":"aGKU-o9eXB1VHuN9@kitsune.suse.cz","threadId":"63712","inReplyTo":null,"subject":"Failing to push to a repository erases authentication helper credentials","fromName":"Michal Suchánek","fromEmail":"msuchanek@suse.de","sentAt":"2025-06-30T13:45:30Z","receivedAt":"2025-06-30T13:45:33Z","isPatch":false,"sender":{"key":"msuchanek@suse.de","avatar":"https://avatars.githubusercontent.com/u/787652?v=4"},"body":"\nHello,\n\nI was trying out AGit https://docs.gitea.com/usage/agit with oauth\nhelper https://github.com/hickford/git-credential-oauth encountering\nthis bug https://github.com/go-gitea/gitea/issues/34583\n\nWhen doing so the oauth helper asked for new authentication, then for\nsome reason I was asked for authentication by some other helper.\n\nAfter that pushing to repository to which I have permissions asked for\nauthentication again.\n\nThis hints that any failed git operation erases helper credentials.\n\nThat does not sound like a desirable behavior.\n\nCould the previous credentials be preserved?\n\nThanks\n\nMichal\n"},{"id":"520922","messageId":"aGKfs5VRdmnw6Pqc@fruit.crustytoothpaste.net","threadId":"63712","inReplyTo":"aGKU-o9eXB1VHuN9@kitsune.suse.cz","subject":"Re: Failing to push to a repository erases authentication helper credentials","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2025-06-30T14:31:15Z","receivedAt":"2025-06-30T14:31:17Z","isPatch":false,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2025-06-30 at 13:45:30, Michal Suchánek wrote:\n> I was trying out AGit https://docs.gitea.com/usage/agit with oauth\n> helper https://github.com/hickford/git-credential-oauth encountering\n> this bug https://github.com/go-gitea/gitea/issues/34583\n> \n> When doing so the oauth helper asked for new authentication, then for\n> some reason I was asked for authentication by some other helper.\n> \n> After that pushing to repository to which I have permissions asked for\n> authentication again.\n> \n> This hints that any failed git operation erases helper credentials.\n\nThis is true and it's by design.\n\n> That does not sound like a desirable behavior.\n\nIt is in fact desirable because otherwise the user continues to attempt\nto use the bad credentials and then can never again authenticate\nsuccessfully, since they are never again prompted for credentials.\n\n> Could the previous credentials be preserved?\n\nGit doesn't have a behaviour to do so, but you could of course craft a\ncustom credential helper that just rejects the erase command and passes\neverything else through to another helper.  That would achieve your\ngoal.\n-- \nbrian m. carlson (they/them)\nToronto, Ontario, CA\n"},{"id":"520924","messageId":"aGKokqPJPh5fQ3fc@kitsune.suse.cz","threadId":"63712","inReplyTo":"aGKfs5VRdmnw6Pqc@fruit.crustytoothpaste.net","subject":"Re: Failing to push to a repository erases authentication helper credentials","fromName":"Michal Suchánek","fromEmail":"msuchanek@suse.de","sentAt":"2025-06-30T15:09:06Z","receivedAt":"2025-06-30T15:09:11Z","isPatch":false,"sender":{"key":"msuchanek@suse.de","avatar":"https://avatars.githubusercontent.com/u/787652?v=4"},"body":"On Mon, Jun 30, 2025 at 02:31:15PM +0000, brian m. carlson wrote:\n> On 2025-06-30 at 13:45:30, Michal Suchánek wrote:\n> > I was trying out AGit https://docs.gitea.com/usage/agit with oauth\n> > helper https://github.com/hickford/git-credential-oauth encountering\n> > this bug https://github.com/go-gitea/gitea/issues/34583\n> > \n> > When doing so the oauth helper asked for new authentication, then for\n> > some reason I was asked for authentication by some other helper.\n> > \n> > After that pushing to repository to which I have permissions asked for\n> > authentication again.\n> > \n> > This hints that any failed git operation erases helper credentials.\n> \n> This is true and it's by design.\n> \n> > That does not sound like a desirable behavior.\n> \n> It is in fact desirable because otherwise the user continues to attempt\n> to use the bad credentials and then can never again authenticate\n> successfully, since they are never again prompted for credentials.\n\nMy proglem is that the credentials are actually valid, only the\noperation is not. The current behavior erases valid credentials.\n\n> > Could the previous credentials be preserved?\n> \n> Git doesn't have a behaviour to do so, but you could of course craft a\n> custom credential helper that just rejects the erase command and passes\n> everything else through to another helper.  That would achieve your\n\nI do not want to use another helper. I want to preserve the last valid\ncredentials.\n\nOf course, using credentials that are not maintained by git at all (such\nas ssh authentication) does not have this problem. Only git-managed\ncredentials get erased on invalid operation.\n\nThanks\n\nMichal\n"},{"id":"520949","messageId":"aGLXmiYuM2C_xfWJ@fruit.crustytoothpaste.net","threadId":"63712","inReplyTo":"aGKokqPJPh5fQ3fc@kitsune.suse.cz","subject":"Re: Failing to push to a repository erases authentication helper credentials","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2025-06-30T18:29:46Z","receivedAt":"2025-06-30T18:29:48Z","isPatch":false,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2025-06-30 at 15:09:06, Michal Suchánek wrote:\n> On Mon, Jun 30, 2025 at 02:31:15PM +0000, brian m. carlson wrote:\n> > It is in fact desirable because otherwise the user continues to attempt\n> > to use the bad credentials and then can never again authenticate\n> > successfully, since they are never again prompted for credentials.\n> \n> My proglem is that the credentials are actually valid, only the\n> operation is not. The current behavior erases valid credentials.\n\nThen the server needs to return a 403 or 404 and not a 401.  A 401\nprompts Git to expire credentials and a 403 or 404 does not.  Only the\nserver knows whether the credentials are actually valid for some access\nor not at all.\n\nRFC 9110 § 15.5.2 says this:\n\n    The 401 (Unauthorized) status code indicates that the request has\n    not been applied because it lacks valid authentication credentials\n    for the target resource.\n\nand § 15.5.4 says this:\n\n    The 403 (Forbidden) status code indicates that the server understood\n    the request but refuses to fulfill it.\n    […]\n    If authentication credentials were provided in the request, the\n    server considers them insufficient to grant access. The client\n    SHOULD NOT automatically repeat the request with the same\n    credentials. The client MAY repeat the request with new or different\n    credentials.\n    […]\n    An origin server that wishes to \"hide\" the current existence of a\n    forbidden target resource MAY instead respond with a status code of\n    404 (Not Found).\n\nSo the server is incorrect in returning a 401 in this case if the\ncredentials are actually valid for a different operation on the same\nresource.\n\n> > Git doesn't have a behaviour to do so, but you could of course craft a\n> > custom credential helper that just rejects the erase command and passes\n> > everything else through to another helper.  That would achieve your\n> \n> I do not want to use another helper. I want to preserve the last valid\n> credentials.\n> \n> Of course, using credentials that are not maintained by git at all (such\n> as ssh authentication) does not have this problem. Only git-managed\n> credentials get erased on invalid operation.\n\nIn general, Git does not presently offer this functionality.  We could\nin theory accept a patch for a config option that makes this work, but I\nexpect it will lead to hard-to-troubleshoot problems for the exact\nreason I mentioned.  It will also require an update to the Git FAQ to\ndisable that option in the example, since we use the exact same\nmechanism to delete credentials for users who _do_ want to expire\ncredentials.\n-- \nbrian m. carlson (they/them)\nToronto, Ontario, CA\n"},{"id":"520990","messageId":"aGOGMpibpUM2JJuV@kitsune.suse.cz","threadId":"63712","inReplyTo":"aGLXmiYuM2C_xfWJ@fruit.crustytoothpaste.net","subject":"Re: Failing to push to a repository erases authentication helper credentials","fromName":"Michal Suchánek","fromEmail":"msuchanek@suse.de","sentAt":"2025-07-01T06:54:42Z","receivedAt":"2025-07-01T06:54:45Z","isPatch":false,"sender":{"key":"msuchanek@suse.de","avatar":"https://avatars.githubusercontent.com/u/787652?v=4"},"body":"On Mon, Jun 30, 2025 at 06:29:46PM +0000, brian m. carlson wrote:\n> On 2025-06-30 at 15:09:06, Michal Suchánek wrote:\n> > On Mon, Jun 30, 2025 at 02:31:15PM +0000, brian m. carlson wrote:\n> > > It is in fact desirable because otherwise the user continues to attempt\n> > > to use the bad credentials and then can never again authenticate\n> > > successfully, since they are never again prompted for credentials.\n> > \n> > My proglem is that the credentials are actually valid, only the\n> > operation is not. The current behavior erases valid credentials.\n> \n> Then the server needs to return a 403 or 404 and not a 401.  A 401\n> prompts Git to expire credentials and a 403 or 404 does not.  Only the\n> server knows whether the credentials are actually valid for some access\n> or not at all.\n> \n> RFC 9110 § 15.5.2 says this:\n> \n>     The 401 (Unauthorized) status code indicates that the request has\n>     not been applied because it lacks valid authentication credentials\n>     for the target resource.\n> \n> and § 15.5.4 says this:\n> \n>     The 403 (Forbidden) status code indicates that the server understood\n>     the request but refuses to fulfill it.\n>     […]\n>     If authentication credentials were provided in the request, the\n>     server considers them insufficient to grant access. The client\n>     SHOULD NOT automatically repeat the request with the same\n>     credentials. The client MAY repeat the request with new or different\n>     credentials.\n>     […]\n>     An origin server that wishes to \"hide\" the current existence of a\n>     forbidden target resource MAY instead respond with a status code of\n>     404 (Not Found).\n> \n> So the server is incorrect in returning a 401 in this case if the\n> credentials are actually valid for a different operation on the same\n> resource.\n\nIs there any way to see what the server is returning?\n\nAs the repository uses SSL capturing the communication with a proxy\nwould be challenging.\n\nThanks\n\nMichal\n"},{"id":"520997","messageId":"aGOhIxqloEdxUcn6@kitsune.suse.cz","threadId":"63712","inReplyTo":"aGOGMpibpUM2JJuV@kitsune.suse.cz","subject":"Re: Failing to push to a repository erases authentication helper credentials","fromName":"Michal Suchánek","fromEmail":"msuchanek@suse.de","sentAt":"2025-07-01T08:49:39Z","receivedAt":"2025-07-01T08:49:42Z","isPatch":false,"sender":{"key":"msuchanek@suse.de","avatar":"https://avatars.githubusercontent.com/u/787652?v=4"},"body":"On Tue, Jul 01, 2025 at 08:54:42AM +0200, Michal Suchánek wrote:\n> On Mon, Jun 30, 2025 at 06:29:46PM +0000, brian m. carlson wrote:\n> > On 2025-06-30 at 15:09:06, Michal Suchánek wrote:\n> > > On Mon, Jun 30, 2025 at 02:31:15PM +0000, brian m. carlson wrote:\n> > > > It is in fact desirable because otherwise the user continues to attempt\n> > > > to use the bad credentials and then can never again authenticate\n> > > > successfully, since they are never again prompted for credentials.\n> > > \n> > > My proglem is that the credentials are actually valid, only the\n> > > operation is not. The current behavior erases valid credentials.\n> > \n> > Then the server needs to return a 403 or 404 and not a 401.  A 401\n> > prompts Git to expire credentials and a 403 or 404 does not.  Only the\n> > server knows whether the credentials are actually valid for some access\n> > or not at all.\n> > \n> > RFC 9110 § 15.5.2 says this:\n> > \n> >     The 401 (Unauthorized) status code indicates that the request has\n> >     not been applied because it lacks valid authentication credentials\n> >     for the target resource.\n> > \n> > and § 15.5.4 says this:\n> > \n> >     The 403 (Forbidden) status code indicates that the server understood\n> >     the request but refuses to fulfill it.\n> >     […]\n> >     If authentication credentials were provided in the request, the\n> >     server considers them insufficient to grant access. The client\n> >     SHOULD NOT automatically repeat the request with the same\n> >     credentials. The client MAY repeat the request with new or different\n> >     credentials.\n> >     […]\n> >     An origin server that wishes to \"hide\" the current existence of a\n> >     forbidden target resource MAY instead respond with a status code of\n> >     404 (Not Found).\n> > \n> > So the server is incorrect in returning a 401 in this case if the\n> > credentials are actually valid for a different operation on the same\n> > resource.\n> \n> Is there any way to see what the server is returning?\n> \n> As the repository uses SSL capturing the communication with a proxy\n> would be challenging.\n\nmitmweb works for the purpose but it's hard to interprete the data.\n\n401 is often returned even in the cases when everything works correctly,\nprobably because git first tries to access without authentication.\n\n403 is not ever returned, the error only happens on the git protocol\nlevel, apparently.\n\nThanks\n\nMichal\n"},{"id":"521069","messageId":"xmqqjz4rly5a.fsf@gitster.g","threadId":"63712","inReplyTo":"aGOGMpibpUM2JJuV@kitsune.suse.cz","subject":"Re: Failing to push to a repository erases authentication helper credentials","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-01T15:38:09Z","receivedAt":"2025-07-01T15:38:11Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michal Suchánek <msuchanek@suse.de> writes:\n\n> Is there any way to see what the server is returning?\n\nIf this is going over http(s)://, then\n\n    export GIT_TRACE_CURL=true\n\n(or the absolute path name of the file you want to store the trace\ndata in, in place for true that tells it to dump to the standard\nerror stream), perhaps?\n"},{"id":"521255","messageId":"aGZfFNRvDlFLvlBm@kitsune.suse.cz","threadId":"63712","inReplyTo":"xmqqjz4rly5a.fsf@gitster.g","subject":"Re: Failing to push to a repository erases authentication helper credentials","fromName":"Michal Suchánek","fromEmail":"msuchanek@suse.de","sentAt":"2025-07-03T10:44:36Z","receivedAt":"2025-07-03T10:44:38Z","isPatch":false,"sender":{"key":"msuchanek@suse.de","avatar":"https://avatars.githubusercontent.com/u/787652?v=4"},"body":"On Tue, Jul 01, 2025 at 08:38:09AM -0700, Junio C Hamano wrote:\n> Michal Suchánek <msuchanek@suse.de> writes:\n> \n> > Is there any way to see what the server is returning?\n> \n> If this is going over http(s)://, then\n> \n>     export GIT_TRACE_CURL=true\n> \n\nWith that I can see that the forge instance in question reports\nindiscriminately 401 while their demo site running the current\ndevelopment code correctly returns 403.\n\nProbably a case for upgrading to a more recent version.\n\nThanks\n\nMichal\n"}]}