mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-15 20:09:18 -05:00
Improving authentication with hardware keys / FIDO2 / webauthn + 2FA #9776
Open
opened 2025-11-02 08:49:16 -06:00 by GiteaMirror
·
8 comments
No Branch/Tag Specified
main
release/v1.25
release/v1.24
release/v1.23
release/v1.22
release/v1.21
release/v1.20
release/v1.19
release/v1.18
release/v1.17
release/v1.16
release/v1.15
release/v1.14
release/v1.13
release/v1.12
release/v1.11
release/v1.10
release/v1.9
release/v1.8
v1.25.3
v1.25.2
v1.25.1
v1.25.0
v1.24.7
v1.25.0-rc0
v1.26.0-dev
v1.24.6
v1.24.5
v1.24.4
v1.24.3
v1.24.2
v1.24.1
v1.24.0
v1.23.8
v1.24.0-rc0
v1.25.0-dev
v1.23.7
v1.23.6
v1.23.5
v1.23.4
v1.23.3
v1.23.2
v1.23.1
v1.23.0
v1.23.0-rc0
v1.24.0-dev
v1.22.6
v1.22.5
v1.22.4
v1.22.3
v1.22.2
v1.22.1
v1.22.0
v1.23.0-dev
v1.22.0-rc1
v1.21.11
v1.22.0-rc0
v1.21.10
v1.21.9
v1.21.8
v1.21.7
v1.21.6
v1.21.5
v1.21.4
v1.21.3
v1.21.2
v1.20.6
v1.21.1
v1.21.0
v1.21.0-rc2
v1.21.0-rc1
v1.20.5
v1.22.0-dev
v1.21.0-rc0
v1.20.4
v1.20.3
v1.20.2
v1.20.1
v1.20.0
v1.19.4
v1.21.0-dev
v1.20.0-rc2
v1.20.0-rc1
v1.20.0-rc0
v1.19.3
v1.19.2
v1.19.1
v1.19.0
v1.19.0-rc1
v1.20.0-dev
v1.19.0-rc0
v1.18.5
v1.18.4
v1.18.3
v1.18.2
v1.18.1
v1.18.0
v1.17.4
v1.18.0-rc1
v1.19.0-dev
v1.18.0-rc0
v1.17.3
v1.17.2
v1.17.1
v1.17.0
v1.17.0-rc2
v1.16.9
v1.17.0-rc1
v1.18.0-dev
v1.16.8
v1.16.7
v1.16.6
v1.16.5
v1.16.4
v1.16.3
v1.16.2
v1.16.1
v1.16.0
v1.15.11
v1.17.0-dev
v1.16.0-rc1
v1.15.10
v1.15.9
v1.15.8
v1.15.7
v1.15.6
v1.15.5
v1.15.4
v1.15.3
v1.15.2
v1.15.1
v1.14.7
v1.15.0
v1.15.0-rc3
v1.14.6
v1.15.0-rc2
v1.14.5
v1.16.0-dev
v1.15.0-rc1
v1.14.4
v1.14.3
v1.14.2
v1.14.1
v1.14.0
v1.13.7
v1.14.0-rc2
v1.13.6
v1.13.5
v1.14.0-rc1
v1.15.0-dev
v1.13.4
v1.13.3
v1.13.2
v1.13.1
v1.13.0
v1.12.6
v1.13.0-rc2
v1.14.0-dev
v1.13.0-rc1
v1.12.5
v1.12.4
v1.12.3
v1.12.2
v1.12.1
v1.11.8
v1.12.0
v1.11.7
v1.12.0-rc2
v1.11.6
v1.12.0-rc1
v1.13.0-dev
v1.11.5
v1.11.4
v1.11.3
v1.10.6
v1.12.0-dev
v1.11.2
v1.10.5
v1.11.1
v1.10.4
v1.11.0
v1.11.0-rc2
v1.10.3
v1.11.0-rc1
v1.10.2
v1.10.1
v1.10.0
v1.9.6
v1.9.5
v1.10.0-rc2
v1.11.0-dev
v1.10.0-rc1
v1.9.4
v1.9.3
v1.9.2
v1.9.1
v1.9.0
v1.9.0-rc2
v1.10.0-dev
v1.9.0-rc1
v1.8.3
v1.8.2
v1.8.1
v1.8.0
v1.8.0-rc3
v1.7.6
v1.8.0-rc2
v1.7.5
v1.8.0-rc1
v1.9.0-dev
v1.7.4
v1.7.3
v1.7.2
v1.7.1
v1.7.0
v1.7.0-rc3
v1.6.4
v1.7.0-rc2
v1.6.3
v1.7.0-rc1
v1.7.0-dev
v1.6.2
v1.6.1
v1.6.0
v1.6.0-rc2
v1.5.3
v1.6.0-rc1
v1.6.0-dev
v1.5.2
v1.5.1
v1.5.0
v1.5.0-rc2
v1.5.0-rc1
v1.5.0-dev
v1.4.3
v1.4.2
v1.4.1
v1.4.0
v1.4.0-rc3
v1.4.0-rc2
v1.3.3
v1.4.0-rc1
v1.3.2
v1.3.1
v1.3.0
v1.3.0-rc2
v1.3.0-rc1
v1.2.3
v1.2.2
v1.2.1
v1.2.0
v1.2.0-rc3
v1.2.0-rc2
v1.1.4
v1.2.0-rc1
v1.1.3
v1.1.2
v1.1.1
v1.1.0
v1.0.2
v1.0.1
v1.0.0
v0.9.99
Labels
Clear labels
$20
$250
$50
$500
backport/done
💎 Bounty
docs-update-needed
good first issue
hacktoberfest
issue/bounty
issue/confirmed
issue/critical
issue/duplicate
issue/needs-feedback
issue/not-a-bug
issue/regression
issue/stale
issue/workaround
lgtm/need 2
modifies/api
modifies/translation
outdated/backport/v1.18
outdated/theme/markdown
outdated/theme/timetracker
performance/bigrepo
performance/cpu
performance/memory
performance/speed
pr/breaking
proposal/accepted
proposal/rejected
pr/wip
pull-request
reviewed/wontfix
💰 Rewarded
skip-changelog
status/blocked
topic/accessibility
topic/api
topic/authentication
topic/build
topic/code-linting
topic/commit-signing
topic/content-rendering
topic/deployment
topic/distribution
topic/federation
topic/gitea-actions
topic/issues
topic/lfs
topic/mobile
topic/moderation
topic/packages
topic/pr
topic/projects
topic/repo
topic/repo-migration
topic/security
topic/theme
topic/ui
topic/ui-interaction
topic/ux
topic/webhooks
topic/wiki
type/bug
type/deprecation
type/docs
type/enhancement
type/feature
type/miscellaneous
type/proposal
type/question
type/refactoring
type/summary
type/testing
type/upstream
Mirrored from GitHub Pull Request
Milestone
No items
No Milestone
Projects
Clear projects
No project
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: github-starred/gitea#9776
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @noerw on GitHub (Nov 3, 2022).
The Problem
Possbile Solutions
(1) The Very Simple Fix
Revert #11573, but otherwise leave the auth conditions as they are. Fixes the UI inconsistency and the no-backup code situation, implements github's authentication logic, but does not enable passwordless login and makes phishable credentials mandatory.
(2) The Somewhat Simple Fix
This mostly keeps the current auth logic, except for requiring a backup second factor to be set up:
This auth logic does not require phishable credentials.
(3) The Correct Solution
The most correct way imho would be to implement the auth logic that is outlined below as Nextcloud's implementation.
Effectively the needed changes would be:
This would result in the following auth logic:
Of course not all of those credentials need to be used, all but one from each block could be unavailable/unknown. This option has the benefit to get along without mandatory phishable credentials (password, TOTP), as well as enabling passwordless auth.
Context
Gitea's current (as of 1.18.0+dev-558-g94d6d93cc,
94d6d93cc) authentication behaviour is as follows:username && pwusername && pw && (totp || backupkeys)username && pw && (fidokey1 || fidokey2)username && pw && (fidokey1 || fidokey2 || totp || backupcodes)For reference some other implementations of FIDO2:
username && pw && emailed-tokenusername && pw && (totp || backupkeys)username && pw && (fidokey1 || fidokey2 || totp || backupcodes)username && pwusername && pw && (totp || backupkeys)username && (pw || fidokey1 || fidokey2)username && (pw || fidokey1 || fidokey2) && (totp || backupcodes)As you can see, there is no clear correct de-facto implementation, I have yet to check fido2/webauthn spec if there is a
correctapproved way of implementing things. However there is a strong preference in the wider community on how to do things correctly with security and usability in mind:@lunny commented on GitHub (Nov 4, 2022):
I would like the first implementation(github, mastodon), nextcloud's looks like a 3FA when TOTP 2FA enabled & fido2 keys registered@noerw commented on GitHub (Nov 4, 2022):
If you look closely, you see that it's still 2FA:
username && (pw || fidokey1 || fidokey2) && (totp || backupcodes).The decision here is how much effort the gitea project is willing to put into changing this auth logic, with the possible gain of having an unphishable authentication method (to be clear, Gitea currently has this property (since #11573), so we should think hard about dropping it).
That said, I don't think touching this is urgent, as there is no acute security issue with the current way this auth is handled, the UI is just misleading currently. So it may be beneficial to wait and do this properly once the resources or priority for it are there, and refactor the UI in the meantime.
@theAkito commented on GitHub (Dec 3, 2022):
Was about to create a dedicated issue, but found this one, when searching for existing ones, so I'll add another improvement.
If you need a separate issue out of this, I'll make one.
Gitea's WebAuthn does not save the domain string.
Information about the topic follows.
@lunny commented on GitHub (Mar 8, 2023):
Gitea's auth has a more complex situation. Some users want to login with a third auth server i.e. OAuth2 . I think we need to put all these situations together when refactoring/redesigning.
@f0sh commented on GitHub (Jul 19, 2023):
I would like to catch up on the statement of the beginning of this issue:
Webauthn was designed as a generic, phishing proof protocol and therefore can be used for passwordless authentication. It brings it's own function of a 2nd factor (where you can use a 2F to access your local public key) but is also downward compatible as a 2F with U2F. That's a bit confusing. Because the domain is (as the relying party RP) fundamental part of the authentication process in webauthn, there is a drastically reduced attack vector for phishing in webauthn compared to U2F, because you just cannot use your credentials on a different site, without tampering your local machine.
When it comes to the implementation, then you actually do not use (or strictly saying, you do not have to use) a username anymore, because you are working with a publickey authentication approach.
So I totally agree with what @lunny said, that
because there would be actually a pool of equal authentication methods/backends, every with their own set of credentials:
This is indeed a lot of effort to implement. However, considering the move of bigtechs towards Passkeys and being already available on most platforms, this is worth the discussion and integration. Github just announced few days ago, that they now support passkey authentification as well. Paypal, Google, Apple are alreading doing it.
My point is, when tackling the described issues, I would suggest to refactor it in a way that the whole picture is considered as it is discussed in #24821. I think this will give more momentum. A first approach can be hanko.io.
@ptman commented on GitHub (May 20, 2025):
Seems like passkeys / webauthn is registered without verification required. So I'm able to login using my yubikey by just plugging it in and pressing the button WITHOUT entering my pin. So this makes it a 1FA instead of 2FA. Posession of yubikey is enough, without need to know pin. (I don't have a biometric yubikey)
0534eddd16/routers/web/user/setting/security/webauthn.go (L56)https://pkg.go.dev/github.com/go-webauthn/webauthn@v0.13.0/protocol#UserVerificationRequirement
@iddm commented on GitHub (Jun 28, 2025):
Isn't the first factor your password? So you must know your user's login and password, AND have access to the smart card associated with his account.
@ptman commented on GitHub (Jul 2, 2025):
I'm not asked for a password. Passkeys are supposed to allow passwordless login, but in those cases the authenticator should do some sort of check (face, fingerprint, PIN, ...)