# webauthn-framework: passkey authentication for PHP and Symfony

> webauthn-framework is a set of PHP libraries and a Symfony bundle that implement WebAuthn, FIDO2 and the older U2F protocol so a PHP application can use hardware security keys or platform authenticators for sign-in. It ships as a set of Composer packages with a matching JavaScript asset bundle, and the maintainer publishes a supported-version list per release line.

**web-auth/webauthn-framework** — FIDO-U2F / FIDO2 / Webauthn Framework

- Repository: https://github.com/web-auth/webauthn-framework
- Stars: 522 · Forks: 82
- Language: PHP
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/web-auth-webauthn-framework

## What the framework covers and what it does not

The README opens by restating the specification's purpose. Webauthn defines an API enabling the creation and use of strong, attested, scoped, public key-based credentials by web applications, for the purpose of strongly authenticating users. This framework contains PHP libraries and a Symfony bundle to allow developers to integrate that authentication mechanism into their web applications.

So the scope is authentication, and specifically the public-key credential half of it. A WebAuthn authenticator holds a key pair, the private key never leaves the device, and the server stores a public key plus a credential identifier. What the server can then do is verify a signature, and the browser API that drives it is the WebAuthn API.

The name of the repository, webauthn-framework, is broader than the README's framing, and the topic tags explain why. Alongside webauthn and webauthn-support there are fido-u2f and u2f-protocol, plus fido2. Those are the protocol generations the library covers: U2F was the original FIDO security key standard, FIDO2 is the current one, and WebAuthn is the browser API that replaced the U2F JavaScript API. Supporting all three matters in practice because authenticators and relying parties in the wild still mix them, and because a migration from a U2F deployment to WebAuthn is a server-side change.

The primary language is PHP, the licence is MIT, the default branch is 5.4.x, and the recent releases are 5.3.9 from 2026-09-10, 5.3.8 and 5.3.7 both from 2026-08-30. The last push was on 2026-10-01.

The documentation is hosted separately at webauthn-doc.spomky-labs.com, and the README is candid that it is a pointer document rather than a manual. The supported-version list is likewise external, in RELEASES.md, with the README noting that the list of supported versions is available on that page.

That last point deserves attention. For a security library, the set of PHP, Symfony and platform versions a given release line supports is not a nicety, and a project that keeps that list in a versioned file per branch is doing the right thing by making it reviewable.

## The Composer package layout and the JavaScript half

The repository layout shows how the pieces fit, and the split between PHP and JavaScript is the first thing to understand.

There is a src/ directory holding the PHP packages, and the package.json in the root declares workspaces over src/*/assets, which is where the JavaScript lives. That means the browser-side code ships as part of the same Composer distribution, which is what makes the Symfony bundle and the standalone libraries usable from the same repository.

The JavaScript toolchain is described in the package.json scripts.

```json
    "scripts": {
        "test": "npm exec -ws -- jest",
        "lint:fix": "npm exec -ws -- eslint src test --fix",
        "lint": "npm exec -ws -- eslint src test --no-fix",
```

So the front end is a set of npm workspaces run with jest for tests and eslint for linting, and the styles are set in the same file with a printWidth of 120, a tabWidth of 4, singleQuote enabled and bracketSameLine on.

The dependency list explains the shape of the front end. Babel with the env and react presets, jest with the jsdom environment, and @symfony/stimulus-testing are the core of a Stimulus-based bundle, which is how a Symfony application would wire up the WebAuthn ceremony without writing framework-specific glue.

The PHP side is less visible in the README, but the presence of a castor.php file and a bin/ directory points at a task runner and a console entry point, and the .gitsplit.yml indicates the repository is split into smaller packages at release time. That last file is the mechanism behind the multiple Composer packages: one repository, several distributions, which is how you end up with a library set where a project takes only the pieces it needs.

There is a CLAUDE.md at the root, so the project is developed with an AI coding assistant in the loop, and there is a dedicated SECURITY.md with the disclosure process described below.

## What the repository tree reveals about the design

The top-level entries describe a repository that is more than a single library, and reading them tells you how the project is put together.

There is src/, which holds the PHP packages, and the root package.json declares workspaces over src/*/assets, so the JavaScript for each package sits alongside its PHP code. That pairing is the key structural decision: a WebAuthn integration is half server and half browser, and keeping them in the same distribution removes the failure mode where the two drift apart.

The .gitsplit.yml file is the other structural hint. It is the configuration for splitting one repository into several, which is how a set of Composer packages comes out of one codebase with one history and one release process. The topic tags support this reading, naming webauthn-library and webauthn-bundle as separate concerns: the plain library for people who are not using Symfony, and the bundle for people who are.

There is a docs/ directory for the documentation sources, and a link directory at the root. There is a bin/ directory, which holds console entry points, and a castor.php file, which is a PHP task runner used for development scripts. That combination tells you the project has a working developer workflow for building, testing and releasing several packages at once, which is more infrastructure than most single-purpose libraries carry.

The .ci-tools/ directory and the .github/ directory hold the continuous integration configuration, and the jest.config.cjs, babel.config.cjs and eslint.config.js files are all in the root, which is what you would expect for a monorepo where the JavaScript tooling is shared across the workspaces.

The tests/ directory at the root holds the PHP test suite, and src/*/assets holds the JavaScript tests alongside the frontend code.

One structural point worth calling out is what is not there. There is no application, no demo site and no server component in the tree, only libraries, a bundle, tests and tooling. This is a project that is meant to be a dependency, and evaluating it as a product to run would be a mistake.

## Security disclosure and the supported-version policy

Two sections of the README are about process rather than code, and for a project in this category they are the parts a security engineer will read first.

The first is the security reporting route. If you discover a security vulnerability within the project, the README asks that you do not use the bug tracker and do not publish it publicly. Instead, all security issues must be sent via the GitHub Vulnerability Report system.

That is the correct instruction, and it is worth noting what it implies about the project. A WebAuthn implementation that has a flaw in signature verification or in the credential storage layer is a complete authentication bypass, so the disclosure channel matters more here than it would for a utility library. The private report route also lets the maintainer ship a fix before the details are public.

The second is the supported-version policy, which is maintained per branch in RELEASES.md. The default branch here is 5.4.x, while the published tags are on the 5.3.x line, which is a normal pattern for a project that maintains an in-development major line alongside a supported one.

The consequence for an adopter is that the branch you depend on and the branch you read documentation for are not the same thing, and the supported-version list is the document that tells you which combinations of PHP, Symfony and platform are actually tested. A framework that pins supported combinations per release is taking the maintenance burden seriously, because a WebAuthn library that breaks on a PHP upgrade is a security incident waiting to happen.

There is also a CODE_OF_CONDUCT.md, and the tests/ directory in the root tree, which is where the PHP test suite lives.

One thing the README does not state is the exact dependency list for the PHP packages. The composer.json is present in the tree but its contents are not shown in the README, so the specific Symfony version range and the PHP version floor for each release line are things to confirm from the package metadata rather than assume.

## Where webauthn-framework is the wrong choice

There are three limits, and the first is about what WebAuthn itself commits you to.

The first is that passwordless authentication is a protocol, not a feature toggle. A WebAuthn sign-in has a registration ceremony and an authentication ceremony, each with several steps the browser and the authenticator perform, and the server has to store a credential public key, a credential id, a sign count and the user handle. There is no recovery path when a user loses every authenticator, so you need a fallback: a recovery code, a second key, or a more conventional second factor. That is a product design decision with security consequences, and it does not get smaller because a library implements the hard parts.

The second is the maintenance surface of the packages. The repository publishes multiple Composer packages from one source, with per-branch supported-version lists and a private vulnerability reporting process. That is the profile of a library that expects to be maintained across many dependency combinations, and it is a genuinely heavier thing to depend on than a single-purpose package. For a team whose entire authentication requirement is a second factor alongside a password, this is a large amount of machinery for the job.

The third is that the browser side has to be right. The JavaScript bundle in src/*/assets is what initiates the ceremony in the browser, and the PHP library is what verifies it. A mismatch between the two, or a deployment where the asset bundle is stale, produces failures that look like authentication problems. Because the assets ship from the same Composer package as the PHP code, that risk is reduced, but it means the frontend build is part of your release process rather than something you can ignore.

The honest alternative depends on the constraint. For a PHP application that wants to support security keys without implementing the protocol, this framework is the direct answer, and it is a more focused dependency than a full identity platform. For an application that already has an identity provider with WebAuthn support, using that provider's passkeys and treating your application as an OAuth client avoids implementing credential storage and ceremony handling altogether.

For an application that only needs a second factor and does not need phishing-resistant authentication, a TOTP implementation is much simpler and the risk profile is well understood, with the trade-off that it is not phishing resistant against a credential-filling attack.

What this framework offers over writing it yourself is the part nobody should write twice: the U2F, FIDO2 and WebAuthn protocol handling across their generation differences, the Symfony integration, and the browser bundle that goes with it. The decision is whether passkey authentication is the right answer for your product, and for a PHP team that has decided it is, this is the library that covers the protocol rather than a thin wrapper around a service.

## Conclusion

Adopt webauthn-framework if you run a PHP or Symfony application and want WebAuthn sign-in with hardware keys or passkeys, since it implements the protocol and ships both a server library and the browser-side asset bundle. Do not adopt it for a simple application that needs one factor and a password reset flow, because the ceremony handling and credential storage are a lot of surface for that. Before you start, read RELEASES.md for the supported version list of your branch, since the default branch is 5.4.x while the published releases are 5.3.x.

## FAQ

### What is webauthn-framework?

It is a set of PHP libraries and a Symfony bundle for integrating WebAuthn into web applications, covering the FIDO-U2F, FIDO2 and WebAuthn protocol generations. The README describes it as enabling the creation and use of strong, attested, scoped, public key-based credentials for strongly authenticating users.

### How is the JavaScript side of the webauthn-framework distributed?

The browser assets live in npm workspaces under src/*/assets, declared in the root package.json, and are built and tested with jest, eslint and prettier. Because the assets are part of the same Composer distribution, the front end and the PHP verification code ship together.

### Which versions of PHP and Symfony does webauthn-framework support?

The supported versions are maintained per release line in RELEASES.md, which the README links to rather than reproducing. The default branch is 5.4.x while the published releases are on the 5.3.x line, so you need the list for the branch you depend on.

### How should a security vulnerability in webauthn-framework be reported?

The README asks that you do not use the bug tracker and do not publish it publicly. All security issues must be sent via the GitHub Vulnerability Report system linked from the README.

### What licence is webauthn-framework released under?

The README states that the project is released under the MIT licence, with the full text in the LICENSE file at the root of the repository.

## Sources

- [Issues](https://github.com/web-auth/webauthn-framework/issues)
- [License: MIT](https://github.com/web-auth/webauthn-framework/blob/5.4.x/LICENSE)
- [README](https://github.com/web-auth/webauthn-framework/blob/5.4.x/README.md)
- [Releases](https://github.com/web-auth/webauthn-framework/releases)
- [web-auth/webauthn-framework on GitHub](https://github.com/web-auth/webauthn-framework)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/web-auth-webauthn-framework
