Gitea Version
1.26.0
What happened?
Summary. Adding a roaming FIDO2 security key (Settings → Security → "Two-Factor Authentication (Security Keys)") succeeds, but login with that key fails at the 2FA step (/user/webauthn):
- Windows dialog: "This security key isn't recognized."
- Page:
NotAllowedError: The operation either timed out or was not allowed.
This looks like the login-side counterpart of #35362. There, registration fails for authenticators that can't create resident credentials, because Gitea requests authenticatorSelection.residentKey: "required". My authenticator (Rutoken MFA) does support resident keys, so registration succeeds — but the subsequent assertion (login) is rejected.
Steps to reproduce
- Settings → Security → add a security key (Windows: choose "Security key", touch + PIN). Registration succeeds; the key is listed.
- Sign out; sign in with username + password.
- At the WebAuthn 2FA prompt, touch the same key →
NotAllowedError; login is impossible. (TOTP, when also enrolled, works.)
Expected: login completes with the registered key.
Actual: the platform rejects the key as not matching any credential.
Relevant config: ROOT_URL=https://git.example.com/, HTTP_ADDR=127.0.0.1, no [webauthn]/RP_ID override (rpId derived from ROOT_URL = git.example.com, correct). HTTPS via nginx, valid TLS.
Isolation — the authenticator works against a reference RP. The same Rutoken MFA authenticates on webauthn.io in every configuration I tested:
| Credential |
userVerification |
webauthn.io |
| discoverable (resident) |
preferred |
works |
| non-discoverable |
preferred |
works |
| non-discoverable |
discouraged |
works |
Honest gap: the one combination matching Gitea's actual flow — a resident credential (Gitea registers Security Keys with residentKey: "required", see #35362) asserted with userVerification: "discouraged" — is the single combination I did not independently reproduce on webauthn.io. The three above all pass.
Assertion options Gitea returns at login (captured from the assertion fetch on /user/webauthn; credential id + challenge redacted):
{
"challenge": "<redacted>",
"timeout": 120000,
"rpId": "git.example.com",
"allowCredentials": [{ "type": "public-key", "id": "dZBDl…FarGn" }],
"userVerification": "discouraged"
}
rpId is correct; allowCredentials carries the registered credential id (no transports field).
Analysis (evidence, not a verdict). The authenticator and each individually-tested parameter work against a reference RP, yet Gitea's assertion is rejected — so the problem is on Gitea's side, in the Security-Keys WebAuthn flow that #35362 already shows mishandles authenticatorSelection. Candidate mechanisms (not pinned): (1) the credential id Gitea stored/sent does not match the authenticator's actual credential (e.g. a base64 vs base64url round-trip); (2) the resident-credential + userVerification: "discouraged" interaction (the untested combination above).
Version note. 1.26.1 / 1.26.2 changelogs contain no WebAuthn fix; 1.26.3 was in the release pipeline when this was filed (changelog not yet published — worth confirming during triage).
Additional data on request: registration (attestation) credential id vs the assertion allowCredentials.id (to confirm/exclude mechanism 1); full un-redacted assertion JSON; docker logs around the failed attempt.
Related: #35362 (same Security-Keys flow, registration-side).
How are you running Gitea?
Docker ( network_mode: host ), PostgreSQL backend, behind an nginx reverse proxy (public HTTPS, HTTP_ADDR=127.0.0.1 ). Client: Windows 11, Chromium (Chrome/Edge), WebAuthn via the Windows platform dialog. Authenticator: Rutoken MFA (FIDO2/CTAP2.1, ES256), AAGUID all-zeros, transports nfc+usb.
Gitea Version
1.26.0
What happened?
Summary. Adding a roaming FIDO2 security key (Settings → Security → "Two-Factor Authentication (Security Keys)") succeeds, but login with that key fails at the 2FA step (
/user/webauthn):NotAllowedError: The operation either timed out or was not allowed.This looks like the login-side counterpart of #35362. There, registration fails for authenticators that can't create resident credentials, because Gitea requests
authenticatorSelection.residentKey: "required". My authenticator (Rutoken MFA) does support resident keys, so registration succeeds — but the subsequent assertion (login) is rejected.Steps to reproduce
NotAllowedError; login is impossible. (TOTP, when also enrolled, works.)Expected: login completes with the registered key.
Actual: the platform rejects the key as not matching any credential.
Relevant config:
ROOT_URL=https://git.example.com/,HTTP_ADDR=127.0.0.1, no[webauthn]/RP_IDoverride (rpId derived from ROOT_URL =git.example.com, correct). HTTPS via nginx, valid TLS.Isolation — the authenticator works against a reference RP. The same Rutoken MFA authenticates on webauthn.io in every configuration I tested:
Honest gap: the one combination matching Gitea's actual flow — a resident credential (Gitea registers Security Keys with
residentKey: "required", see #35362) asserted withuserVerification: "discouraged"— is the single combination I did not independently reproduce on webauthn.io. The three above all pass.Assertion options Gitea returns at login (captured from the
assertionfetch on/user/webauthn; credential id + challenge redacted):{ "challenge": "<redacted>", "timeout": 120000, "rpId": "git.example.com", "allowCredentials": [{ "type": "public-key", "id": "dZBDl…FarGn" }], "userVerification": "discouraged" }rpIdis correct;allowCredentialscarries the registered credential id (notransportsfield).Analysis (evidence, not a verdict). The authenticator and each individually-tested parameter work against a reference RP, yet Gitea's assertion is rejected — so the problem is on Gitea's side, in the Security-Keys WebAuthn flow that #35362 already shows mishandles
authenticatorSelection. Candidate mechanisms (not pinned): (1) the credential id Gitea stored/sent does not match the authenticator's actual credential (e.g. a base64 vs base64url round-trip); (2) the resident-credential +userVerification: "discouraged"interaction (the untested combination above).Version note. 1.26.1 / 1.26.2 changelogs contain no WebAuthn fix; 1.26.3 was in the release pipeline when this was filed (changelog not yet published — worth confirming during triage).
Additional data on request: registration (
attestation) credential id vs the assertionallowCredentials.id(to confirm/exclude mechanism 1); full un-redacted assertion JSON;docker logsaround the failed attempt.Related: #35362 (same Security-Keys flow, registration-side).
How are you running Gitea?
Docker ( network_mode: host ), PostgreSQL backend, behind an nginx reverse proxy (public HTTPS, HTTP_ADDR=127.0.0.1 ). Client: Windows 11, Chromium (Chrome/Edge), WebAuthn via the Windows platform dialog. Authenticator: Rutoken MFA (FIDO2/CTAP2.1, ES256), AAGUID all-zeros, transports nfc+usb.