PHPackages                             wpconsulting/passkey-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. wpconsulting/passkey-bundle

ActiveComposer-plugin[Authentication &amp; Authorization](/categories/authentication)

wpconsulting/passkey-bundle
===========================

Symfony bundle for WebAuthn platform passkeys (Face ID, Touch ID, Samsung fingerprint, Windows Hello).

v3.0.7(today)011↑2627.3%MITPHPPHP &gt;=8.2CI passing

Since Jul 27Pushed todayCompare

[ Source](https://github.com/williamPeninon/passkey-bundle)[ Packagist](https://packagist.org/packages/wpconsulting/passkey-bundle)[ Docs](https://github.com/williamPeninon/passkey-bundle)[ RSS](/packages/wpconsulting-passkey-bundle/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (14)Versions (7)Used By (0)

WP Consulting Passkey Bundle
============================

[](#wp-consulting-passkey-bundle)

**Language:** [English](README.md) · [Français](README.fr.md)

[![CI](https://github.com/williamPeninon/passkey-bundle/actions/workflows/ci.yml/badge.svg)](https://github.com/williamPeninon/passkey-bundle/actions/workflows/ci.yml)[![Latest Stable Version](https://camo.githubusercontent.com/59465f8b14df62467fd5f57ce2d00406dad6f7b2298bfaccd2bfdaebdd5dbcec/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7770636f6e73756c74696e672f706173736b65792d62756e646c652e737667)](https://packagist.org/packages/wpconsulting/passkey-bundle)[![License](https://camo.githubusercontent.com/01d1b3dcbb56d050c0966483f4da2053262ad5de6e21667439183bbe9a2852d1/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f77696c6c69616d50656e696e6f6e2f706173736b65792d62756e646c652e737667)](LICENSE)

Symfony bundle for **WebAuthn / passkeys** using the device’s platform authenticator:

PlatformMethodMac**Touch ID**iPhone / iPad**Face ID** (or Touch ID)Samsung / Android**Fingerprint** (Credential Manager / Samsung Pass)Windows**Windows Hello**> Unlocking the phone or Mac **does not** create a passkey for your site. Users must **register** a passkey from their logged-in account, on the **same device** and the **same hostname** (RP ID).

---

Requirements
------------

[](#requirements)

- PHP `>= 8.2`
- Symfony `^6.4` or `^7.0`
- Doctrine ORM + Security + Twig + Stimulus (Asset Mapper / UX)

---

Quick install
-------------

[](#quick-install)

```
composer require wpconsulting/passkey-bundle
php bin/console passkey:configure
```

Then add the Twig partials (only remaining manual wiring):

**Login**

```
{% include '@Passkey/passkey/_login_button.html.twig' %}
```

**Account (manage passkeys)**

```
{% include '@Passkey/passkey/_manage.html.twig' with {
    credentials: passkey_credentials(app.user)
} %}
```

### What `passkey:configure` does

[](#what-passkeyconfigure-does)

- publishes `config/packages/wp_consulting_passkey.yaml` and `config/routes/passkey.yaml`
- publishes `config/packages/dev/framework.yaml` (`trusted_proxies` for ngrok — **dev only**)
- registers the bundle in `config/bundles.php` if needed
- asks for `user_class` + `user_identifier_field`
- implements `PasskeyUserInterface` on the User entity
- enables Stimulus controllers in `assets/controllers.json`
- adds `PUBLIC_ACCESS` for `^/webauthn/login`
- creates the `web_authn_credential` table (`passkey:install` / migrations)

```
# Examples
php bin/console passkey:configure --user-class=App\\Entity\\User
php bin/console passkey:configure --no-db
php bin/console passkey:configure -n   # non-interactive if user_class is already in YAML
```

### Flex (optional)

[](#flex-optional)

To also copy YAML via Symfony Flex:

```
{
    "extra": {
        "symfony": {
            "endpoint": [
                "https://raw.githubusercontent.com/williamPeninon/passkey-bundle/main/flex/index.json",
                "flex://defaults"
            ]
        }
    }
}
```

Without a custom endpoint, Flex may show an `auto-generated recipe` — that is fine. The Composer plugin then prints the post-install message (`passkey:configure` + details). Allow it if Composer asks:

```
{
    "config": {
        "allow-plugins": {
            "wpconsulting/passkey-bundle": true
        }
    }
}
```

---

Configuration
-------------

[](#configuration)

```
# config/packages/wp_consulting_passkey.yaml
wp_consulting_passkey:
    user_class: App\Entity\User          # entity FQCN, not a namespace
    user_identifier_field: email         # Doctrine field used for login lookup
    rp_name: 'My App'
    login_authenticator: form_login
    default_redirect_route: app_account
    # success_handler: App\Security\LoginSuccessHandler
    translation_domain: PasskeyBundle
    translation_prefix: ''
    email_input_selector: '#username, input[name="_username"], input[name="email"], input[type="email"]'
```

OptionPurpose`user_class`User entity (must implement `PasskeyUserInterface`)`user_identifier_field`Field used at WebAuthn login (`email`, `username`, …)`rp_name`Name shown in the passkey dialog`login_authenticator`Security authenticator passed to `Security::login()``default_redirect_route`Redirect after biometric login`success_handler`Optional post-login handler`email_input_selector`CSS selectors for the identifier field on the login formUntil `user_class` is a valid class implementing `PasskeyUserInterface`, business services are not wired: `cache:clear` / `asset-map:compile` still work. The `passkey:configure` command is **always** available.

### User

[](#user)

```
use WpConsulting\PasskeyBundle\Contract\PasskeyUserInterface;

class User implements UserInterface, PasswordAuthenticatedUserInterface, PasskeyUserInterface
{
    public function getUserId(): mixed
    {
        return $this->id;
    }

    public function getUserName(): ?string
    {
        return $this->email;
    }

    public function getUserDisplayName(): string
    {
        return (string) $this->getUserName();
    }
}
```

### Security / firewalls

[](#security--firewalls)

`passkey:configure` adds:

```
access_control:
    - { path: ^/webauthn/login, roles: PUBLIC_ACCESS }
```

If you have a **separate admin firewall**, share the session context:

```
security:
    firewalls:
        main: { /* … */ }
        admin:
            pattern: ^/admin
            context: main
```

Otherwise the session created on `/webauthn/*` is invisible to admin → 401/403.

### Database

[](#database)

```
php bin/console passkey:install
# or
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
```

Check:

```
php bin/console doctrine:mapping:info
# → WpConsulting\PasskeyBundle\Entity\WebAuthnCredential
```

---

Twig
----

[](#twig)

### Login — `_login_button.html.twig`

[](#login--_login_buttonhtmltwig)

```
{% include '@Passkey/passkey/_login_button.html.twig' with {
    redirect_url: path('app_account'),
    show_divider: true
} %}
```

Options: `email_input`, `redirect_url`, `button_class`, `show_hint`, `show_divider`, i18n messages…

### Account — `_manage.html.twig`

[](#account--_managehtmltwig)

```
{% include '@Passkey/passkey/_manage.html.twig' with {
    credentials: passkey_credentials(app.user)
} %}
```

Options: `add_button_class`, `wrapper_class`, i18n labels…

### Helpers

[](#helpers)

HelperDescription`passkey_credentials(user)`List of passkeys`passkey_manager``PasskeyManager` service`passkey_redirect_path`Post-login redirect URL`passkey_email_input_selector`Email CSS selectors`passkey_translation_domain`Translation domainCTA translations: `PasskeyBundle` (`fr`, `en`, `es`, `de`).

### CSS

[](#css)

Bundled styles (`assets/styles/passkey.css`), loaded via Stimulus `autoimport`.

```
.passkey-manage {
    --pk-accent: #0f766e;
    --pk-ink: #1a2332;
}
```

---

How it works
------------

[](#how-it-works)

1. Classic login (email / password).
2. On the account page, **Add** Touch ID / Face ID / fingerprint.
3. System dialog → public key stored in the DB (`web_authn_credential`).
4. On `/login`, the biometric button calls `navigator.credentials.get` and authenticates the user.

Device unlockSite passkeyRoleOpens the screen / MacSigns in to the **app account**WhereSystem settingsAccount page **on the site**Tied toThe deviceAccount + **hostname** (RP ID)A passkey created on `localhost` **does not work** on `xxx.ngrok-free.app` or production (different RP ID): re-register on each hostname.

---

Platforms
---------

[](#platforms)

### Mac (Touch ID)

[](#mac-touch-id)

- Touch ID sensor + recent Safari / Chrome.
- Open the site at `http://localhost:…` or `https://localhost:…` (**not** `127.0.0.1`).
- No Face ID on Mac.

### iPhone / iPad (Face ID)

[](#iphone--ipad-face-id)

- Safari (or Chrome iOS / WebKit).
- Same hostname as login; public HTTPS or ngrok tunnel **without** `--host-header=localhost`.

### Samsung / Android (fingerprint)

[](#samsung--android-fingerprint)

- Web passkeys = **fingerprint** (strong biometrics), not lock-screen face unlock.
- Chrome / Samsung Internet over HTTPS.
- “No biometrics” on login = **no passkey registered** for this account / device / hostname.

### Windows Hello

[](#windows-hello)

- Fingerprint, PIN, or camera depending on hardware; Edge / Chrome.

DeviceUI labelPasskey methodMacTouch IDMac fingerprintiPhone / iPadFace IDFace / Touch IDSamsungSamsung FingerprintFingerprintAndroidFingerprintFingerprintWindowsWindows HelloHello---

Local dev &amp; ngrok
---------------------

[](#local-dev--ngrok)

- **Forbidden:** `127.0.0.1`, bare IPs → invalid WebAuthn domain.
- **OK:** `localhost`, public HTTPS hostname.
- **ngrok:** do not force `Host: localhost`; the Host / `X-Forwarded-Host` seen by Symfony must be the public hostname.
- In dev, `passkey:configure` may publish `config/packages/dev/framework.yaml` (`trusted_proxies`). **Do not reuse those values in prod** — see [SECURITY.md](SECURITY.md).

**Web-only** passkeys do **not** require a Google Cloud / OAuth project. Google OAuth or Digital Asset Links only apply to Google Sign-In / native apps linked to the site.

---

Commands
--------

[](#commands)

CommandPurpose`passkey:configure`Full host-app wiring`passkey:install`Creates only the `web_authn_credential` table---

Migration from `touch-id-bundle`
--------------------------------

[](#migration-from-touch-id-bundle)

Previous package: `wpconsulting/touch-id-bundle` (abandoned).

```
composer remove wpconsulting/touch-id-bundle
composer require wpconsulting/passkey-bundle:^3.0
php bin/console passkey:configure
```

Update Twig includes (`@Passkey/passkey/…`) and the `PasskeyUserInterface` interface.

Details: [CHANGELOG.md](CHANGELOG.md).

---

Security &amp; contributing
---------------------------

[](#security--contributing)

- Reporting: [SECURITY.md](SECURITY.md)
- Changelog: [CHANGELOG.md](CHANGELOG.md)
- Issues: [GitHub Issues](https://github.com/williamPeninon/passkey-bundle/issues)
- Tests: `composer test`

```
composer install
composer test
```

---

License
-------

[](#license)

MIT © [WP Consulting](https://www.linkedin.com/in/william-peninon-cto-yuno)

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance100

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

6

Last Release

0d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/0a85b5151c901c381b31b169b676b77b44260da67c6fb7bd768f14adb3874261?d=identicon)[williamPeninon](/maintainers/williamPeninon)

---

Top Contributors

[![williamPeninon](https://avatars.githubusercontent.com/u/4995177?v=4)](https://github.com/williamPeninon "williamPeninon (48 commits)")

---

Tags

symfonysymfony-uxAuthenticationflexwebauthnpasskeywindows hellobiometricface-id

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/wpconsulting-passkey-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/wpconsulting-passkey-bundle/health.svg)](https://phpackages.com/packages/wpconsulting-passkey-bundle)
```

###  Alternatives

[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k17.9M401](/packages/easycorp-easyadmin-bundle)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M754](/packages/sylius-sylius)[oro/platform

Business Application Platform (BAP)

645143.5k116](/packages/oro-platform)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.4M215](/packages/sulu-sulu)[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

1189.8k](/packages/rcsofttech-audit-trail-bundle)[open-dxp/opendxp

Content &amp; Product Management Framework (CMS/PIM)

9421.6k64](/packages/open-dxp-opendxp)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
