Support setting the unsolicited output setting to allow invalid client outputs that are not permitted in the spec
Version
v4.39.24, v4.39.26
Deployment Method
Docker
Reverse Proxy
Traefik
Reverse Proxy Version
No response
Description
Passkey authentication via WebAuthn fails on Safari (macOS and iOS) with the following error:
Error occurred validating a WebAuthn passkey authentication challenge:
error performing the login validation
error="Error validating the client extension outputs: Client returned the \"appid\" extension output which was not requested (invalid_request)"The same YubiKey works perfectly on Firefox (Linux, macOS) and Chrome. The problem is specific to WebKit-based browsers (Safari on macOS and iOS, and all browsers on iOS since they are forced to use WebKit).
Root cause
WebKit (Safari) always returns the appId extension output in clientExtensionResults, even when the appid extension was not requested by the Relying Party. The value returned is false when the extension was not used, but the field is still present:
clientExtensionResults: { appId: false }Authelia's WebAuthn validation layer strictly rejects any extension output that was not explicitly requested by the server, which causes the authentication to fail before the signature is even verified.
This behavior is documented in the WebAuthn specification discussions: clients may return unsolicited extension outputs, and Relying Parties SHOULD be prepared to handle this situation, either by ignoring the unsolicited output or by rejecting the assertion based on local policy.
The go-webauthn library used by Authelia already exposes an option to control this behavior:
ExtensionsUnsolicitedOutputPolicy: protocol.UnsolicitedOutputPolicyIgnoreReproduction
- Configure Authelia v4.39.x with:
webauthn.enable_passkey_login: truewebauthn.experimental_enable_passkey_uv_two_factors: trueaccess_control.default_policy: two_factor
- Register a YubiKey as a Passkey from a non-WebKit browser (or directly from Safari — the registration works).
- Attempt to log in from Safari on macOS or any browser on iOS.
- Touch the YubiKey, enter the PIN, touch again.
- Authentication fails with the
appIdextension error.
Expectations
The login should succeed. The unsolicited appId: false output should be ignored, since Authelia never requested the appid extension.
Configuration (Authelia)
webauthn:
display_name: "Authelia"
enable_passkey_login: true
attestation_conveyance_preference: 'indirect'
selection_criteria:
attachment: 'cross-platform'
user_verification: 'preferred'
metadata:
enabled: true
cache_policy: 'relaxed'Build Information
Last Tag: v4.39.26
State: tagged clean
Branch: v4.39.26
Commit: f6fb0a300877e8c3378dc472c02383c75294d84e
Build Number: 58782
Build OS: linux
Build Arch: amd64
Build Compiler: gc
Build Date: Sat, 12 Sep 2026 23:55:42 +1000
Development: false
Extra:
Go:
Version: go1.27.1
Module Path: github.com/authelia/authelia/v4
Executable Path: github.com/authelia/authelia/v4/cmd/autheliaLogs (Authelia)
authelia | time="2026-09-13T23:54:12+02:00" level=debug msg="Loaded Configuration Sources" files="[/config/configuration.yml]" filters="[]"
authelia | time="2026-09-13T23:54:12+02:00" level=debug msg="Logging Initialized" fields.level=debug file= format= keep_stdout=false
authelia | time="2026-09-13T23:54:12+02:00" level=debug msg="Process user information" gid=0 name=root uid=0 username=root
authelia | time="2026-09-13T23:54:12+02:00" level=info msg="Authelia v4.39.26 is starting"
authelia | time="2026-09-13T23:54:12+02:00" level=info msg="Log severity set to debug"
authelia | time="2026-09-13T23:54:12+02:00" level=debug msg="Registering OpenID Connect 1.0 client with client id 'immich' and policy 'two_factor'"
authelia | time="2026-09-13T23:54:12+02:00" level=info msg="Storage schema is being checked for updates"
authelia | time="2026-09-13T23:54:12+02:00" level=info msg="Storage schema is already up to date"
authelia | time="2026-09-13T23:54:13+02:00" level=info msg="Startup complete"
authelia | time="2026-09-13T23:54:13+02:00" level=info msg="Listening for non-TLS connections on '[::]:9091' path '/'" server=main service=server
authelia | time="2026-09-13T23:54:35+02:00" level=error msg="Error occurred validating a WebAuthn passkey authentication challenge: error performing the login validation" error="Error validating the client extension outputs: Client returned the \"appid\" extension output which was not requested (invalid_request)" method=POST path=/api/firstfactor/passkey remote_ip=192.168.10.114 stack="github.com/authelia/authelia/v4/internal/regulation/types.go:48 NewBan\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:70 (*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:70 SecurityHeadersCSPNone.func1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:110 SecurityHeadersNoStore.func1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:34 SecurityHeadersBase.func1\ngithub.com/fasthttp/[email protected]/router.go:441 (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:18 LogRequest.func1\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:42 RecoverPanic.func1\ngithub.com/valyala/[email protected]/server.go:2641 (*Server).serveConnCounted\ngithub.com/valyala/[email protected]/server.go:2329 (*Server).serveConn-fm\ngithub.com/valyala/[email protected]/workerpool.go:225 (*workerPool).workerFunc\ngithub.com/valyala/[email protected]/workerpool.go:197 (*workerPool).getCh.func1\nruntime/asm_amd64.s:1264 goexit"
authelia | time="2026-09-13T23:54:35+02:00" level=debug msg="Mark Passkey authentication attempt made by user ''" method=POST path=/api/firstfactor/passkey remote_ip=192.168.10.114
authelia | time="2026-09-13T23:54:35+02:00" level=error msg="Unsuccessful Passkey authentication attempt by user ''" method=POST path=/api/firstfactor/passkey remote_ip=192.168.10.114 stack="github.com/authelia/authelia/v4/internal/handlers/response.go:503 doMarkAuthenticationAttemptWithRequest\ngithub.com/authelia/authelia/v4/internal/handlers/response.go:486 doMarkAuthenticationAttempt\ngithub.com/authelia/authelia/v4/internal/handlers/handler_firstfactor_passkey.go:200 FirstFactorPasskeyPOST\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:70 (*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:70 SecurityHeadersCSPNone.func1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:110 SecurityHeadersNoStore.func1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:34 SecurityHeadersBase.func1\ngithub.com/fasthttp/[email protected]/router.go:441 (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:18 LogRequest.func1\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:42 RecoverPanic.func1\ngithub.com/valyala/[email protected]/server.go:2641 (*Server).serveConnCounted\ngithub.com/valyala/[email protected]/server.go:2329 (*Server).serveConn-fm\ngithub.com/valyala/[email protected]/workerpool.go:225 (*workerPool).workerFunc\ngithub.com/valyala/[email protected]/workerpool.go:197 (*workerPool).getCh.func1\nruntime/asm_amd64.s:1264Logs (Proxy / Application)
Documentation
Actual behavior
Authelia rejects the assertion with:
Client returned the "appid" extension output which was not requested (invalid_request)Proposed fix
In internal/middlewares/authelia_context.go, in the GetWebAuthnProvider() function, add the following field to the webauthn.Config struct:
config := &webauthn.Config{
RPID: origin.Hostname(),
RPDisplayName: ctx.Configuration.WebAuthn.DisplayName,
RPOrigins: []string{origin.String()},
AttestationPreference: ctx.Configuration.WebAuthn.ConveyancePreference,
ExtensionsUnsolicitedOutputPolicy: protocol.UnsolicitedOutputPolicyIgnore, // <-- add this
// ... rest of the config
}This tells go-webauthn to ignore any extension output that was not explicitly requested by the server. This is consistent with the WebAuthn specification's recommendation for Relying Parties to tolerate unsolicited extension outputs.
I have verified that applying this patch locally (building Authelia from source with this one-line change) fully resolves the issue on Safari macOS and iOS, while Chrome and Firefox continue to work as before.
Environment
- Authelia version: v4.39.26 (also reproduced on v4.39.24)
- Installation: Docker (official
authelia/autheliaimage, replaced binary with a patched build) - Reverse proxy: Traefik v3
- YubiKey model: YubiKey 5 (FIDO2, with PIN and user verification)
- Browsers affected:
- Safari 26.x on macOS 26 (Tahoe) — ❌ fails
- Safari on iOS 26 — ❌ fails
- Any browser on iOS (forced WebKit) — ❌ fails
- Browsers working correctly:
- Firefox on Linux — ✅
- Firefox on macOS — ✅
- Chrome on macOS — ✅
Additional context
- The
appidextension is a FIDO U2F backwards-compatibility extension. It is not needed for pure FIDO2/WebAuthn Passkeys. - The YubiKey in question has no U2F credentials registered; the
appIdfield is emitted unconditionally by WebKit regardless of the authenticator's capabilities. - Setting
attestation_conveyance_preferencetoindirectornonedoes not change the behavior — WebKit still returnsappId: false. - This is not a configuration issue: the same config works on Firefox and Chrome on the same machine, pointing to a WebKit-specific behavior.
Relevant W3C WebAuthn specification discussion
This behavior is explicitly covered by the WebAuthn specification. A merged W3C pull request (PR #1289, "Initial proposal to fix #1287") relaxed the previous strict requirement for Relying Parties to reject responses containing unsolicited extensions.
The updated specification text now states:
"Client platforms MAY enact local policy that sets additional authenticator extensions or client extensions and thus cause values to appear in the authenticator extension outputs or client extension outputs that were not originally specified as part of options.extensions. Relying Parties MUST be prepared to handle such situations, whether it be to ignore the unsolicited extensions or reject the attestation. The Relying Party can make this decision based on local policy and the extensions in use." This means Authelia is free to choose the "ignore" policy for unsolicited extension outputs, and the go-webauthn library already provides the UnsolicitedOutputPolicyIgnore option to do exactly that.
Workaround for users
Until this is fixed upstream, the only workaround is to build Authelia from source with the one-line patch described above, or to use Chrome/Firefox on macOS and accept that Safari/iOS users cannot log in via Passkey.
Generative AI
Yes
Pre-Submission Checklist
I agree to follow the Code of Conduct
This is a bug report and not a support request
I have read the security policy and this bug report is not a security issue or security related issue
I have either included the complete configuration file or I am sure it's unrelated to the configuration
I have either included the complete debug / trace logs or the output of the build-info command if the logs are not relevant
I have provided all of the required information in full with the only alteration being reasonable sanitization in accordance with the Troubleshooting Sanitization reference guide
I have checked for related proxy or application logs and included them if available
I have checked for related issues and checked the documentation
Source: authelia/authelia