{"id":44254262,"url":"https://github.com/netresearch/t3x-nr-passkeys-be","last_synced_at":"2026-05-28T23:01:35.017Z","repository":{"id":337457785,"uuid":"1153719439","full_name":"netresearch/t3x-nr-passkeys-be","owner":"netresearch","description":"TYPO3 extension for passwordless backend authentication via WebAuthn/FIDO2 Passkeys","archived":false,"fork":false,"pushed_at":"2026-05-28T17:38:30.000Z","size":1483,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-28T18:13:49.581Z","etag":null,"topics":["authentication","fido2","passkeys","passwordless","php","typo3","typo3-extension","webauthn"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/netresearch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-02-09T16:08:11.000Z","updated_at":"2026-05-28T17:38:45.000Z","dependencies_parsed_at":"2026-03-17T00:03:52.777Z","dependency_job_id":null,"html_url":"https://github.com/netresearch/t3x-nr-passkeys-be","commit_stats":null,"previous_names":["netresearch/t3x-nr-passkeys-be"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/netresearch/t3x-nr-passkeys-be","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netresearch%2Ft3x-nr-passkeys-be","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netresearch%2Ft3x-nr-passkeys-be/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netresearch%2Ft3x-nr-passkeys-be/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netresearch%2Ft3x-nr-passkeys-be/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/netresearch","download_url":"https://codeload.github.com/netresearch/t3x-nr-passkeys-be/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netresearch%2Ft3x-nr-passkeys-be/sbom","scorecard":{"id":1243147,"data":{"date":"2026-02-09T21:35:51Z","repo":{"name":"github.com/netresearch/t3x-nr-passkeys-be","commit":"5bbca53c6aae6e41edb131f256bab29d01783bc6"},"scorecard":{"version":"v5.3.0","commit":"c22063e786c11f9dd714d777a687ff7c4599b600"},"score":6.4,"checks":[{"name":"Maintained","score":0,"reason":"project was created within the last 90 days. Please review its contents carefully","details":["Warn: Repository was created within the last 90 days."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#code-review"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#security-policy"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dangerous-workflow"}},{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: detected update tool: Dependabot: .github/dependabot.yml:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dependency-update-tool"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql.yml:29","Info: jobLevel 'contents' permission set to 'read': .github/workflows/dependency-review.yml:14","Warn: topLevel 'contents' permission set to 'write': .github/workflows/auto-merge-deps.yml:10","Info: topLevel 'contents' permission set to 'read': .github/workflows/ci.yml:11","Info: topLevel 'contents' permission set to 'read': .github/workflows/codeql.yml:22","Info: topLevel 'contents' permission set to 'read': .github/workflows/dependency-review.yml:7","Info: topLevel 'contents' permission set to 'read': .github/workflows/scorecard.yml:11","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":9,"reason":"dependency not pinned by hash detected -- score normalized to 9","details":["Info: Possibly incomplete results: error parsing shell code: a command can only contain words and redirects; encountered (: .ddev/web-build/Dockerfile:10-115","Warn: containerImage not pinned by hash: .ddev/web-build/Dockerfile:2","Info:  14 out of  14 GitHub-owned GitHubAction dependencies pinned","Info:  16 out of  16 third-party GitHubAction dependencies pinned","Info:   0 out of   1 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#signed-releases"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: SAST configuration detected: CodeQL","Info: all commits (2) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#sast"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#license"}},{"name":"Branch-Protection","score":8,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'main'","Info: 'force pushes' disabled on branch 'main'","Info: 'branch protection settings apply to administrators' is required to merge on branch 'main'","Warn: required approving review count is 1 on branch 'main'","Warn: codeowners review is not required on branch 'main'","Info: status check found to merge onto on branch 'main'","Info: PRs are required in order to make changes on branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#branch-protection"}},{"name":"CI-Tests","score":10,"reason":"1 out of 1 merged PRs checked by a CI test -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#ci-tests"}},{"name":"Contributors","score":6,"reason":"project has 2 contributing companies or organizations -- score normalized to 6","details":["Info: found contributions from: netresearch, oroinc"],"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#contributors"}}]},"last_synced_at":"2026-02-09T22:48:14.600Z","repository_id":337457785,"created_at":"2026-02-09T22:48:14.600Z","updated_at":"2026-02-09T22:48:14.600Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33629560,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","fido2","passkeys","passwordless","php","typo3","typo3-extension","webauthn"],"created_at":"2026-02-10T16:16:51.168Z","updated_at":"2026-05-28T23:01:35.011Z","avatar_url":"https://github.com/netresearch.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.netresearch.de/\"\u003e\n    \u003cimg src=\"Resources/Public/Icons/Extension.svg\" alt=\"Netresearch\" width=\"80\" height=\"80\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003ePasskeys Backend Authentication\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  Passwordless TYPO3 backend login via WebAuthn/FIDO2 Passkeys.\u003cbr\u003e\n  One-click authentication with TouchID, FaceID, YubiKey, and Windows Hello.\n\u003c/p\u003e\n\n\u003c!-- Row 1: CI/Quality badges --\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/netresearch/t3x-nr-passkeys-be/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/netresearch/t3x-nr-passkeys-be/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/netresearch/t3x-nr-passkeys-be\"\u003e\u003cimg src=\"https://codecov.io/gh/netresearch/t3x-nr-passkeys-be/graph/badge.svg\" alt=\"codecov\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003c!-- Row 2: Security badges --\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.bestpractices.dev/projects/12037\"\u003e\u003cimg src=\"https://www.bestpractices.dev/projects/12037/badge\" alt=\"OpenSSF Best Practices\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://securityscorecards.dev/viewer/?uri=github.com/netresearch/t3x-nr-passkeys-be\"\u003e\u003cimg src=\"https://api.securityscorecards.dev/projects/github.com/netresearch/t3x-nr-passkeys-be/badge\" alt=\"OpenSSF Scorecard\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003c!-- Row 3: Standards badges --\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://phpstan.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/PHPStan-Level%2010-brightgreen.svg\" alt=\"PHPStan\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://infection.github.io/\"\u003e\u003cimg src=\"https://img.shields.io/badge/Infection%20MSI-%E2%89%A580%25-brightgreen\" alt=\"Mutation\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.php.net/\"\u003e\u003cimg src=\"https://img.shields.io/badge/PHP-8.2--8.5-blue.svg?logo=php\" alt=\"PHP\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://typo3.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/TYPO3-12%20LTS%20%7C%2013%20LTS%20%7C%2014-orange.svg?logo=typo3\" alt=\"TYPO3\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/netresearch/t3x-nr-passkeys-be/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/netresearch/t3x-nr-passkeys-be\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/netresearch/t3x-nr-passkeys-be/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/netresearch/t3x-nr-passkeys-be\" alt=\"Latest Release\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## Overview\n\n**nr_passkeys_be** replaces traditional password authentication in the TYPO3 backend with modern passkeys. It registers as a TYPO3 authentication service at priority 80, intercepting login requests before the standard password service. When passkey data is present, it performs full WebAuthn assertion verification. Otherwise, it falls through to password login (unless disabled).\n\n|                    |                                          |\n|--------------------|------------------------------------------|\n| **Extension key**  | `nr_passkeys_be`                         |\n| **Package**        | `netresearch/nr-passkeys-be`             |\n| **TYPO3**          | 12.4 LTS, 13.4 LTS, 14.x                |\n| **PHP**            | 8.2, 8.3, 8.4, 8.5                      |\n| **License**        | GPL-2.0-or-later                         |\n\n## Features\n\n- **Primary authentication** -- Passkeys replace passwords, not just augment them\n- **Discoverable login** -- Optional username-less login via resident credentials\n- **Per-group enforcement** -- 4 levels (Off, Encourage, Required, Enforced) with configurable grace periods for gradual rollout\n- **Onboarding banner** -- Dismissible banner with passkey explanation, docs link, and administrator contact for encouraged users\n- **Setup interstitial** -- PSR-15 middleware prompts users to register passkeys after login (skippable during grace period)\n- **Admin dashboard** -- Backend module with adoption stats, per-group enforcement controls, user list, and bulk actions\n- **Admin management** -- Admins can list, revoke passkeys, send reminders, and unlock locked accounts\n- **Self-service** -- Users register, rename, and remove their own passkeys in User Settings\n- **Rate limiting** -- Per-endpoint and per-account lockout protection\n- **Replay protection** -- HMAC-signed challenge tokens with single-use nonces\n\n### Supported Authenticators\n\n| Platform         | Authenticator                             |\n|------------------|-------------------------------------------|\n| macOS / iOS      | TouchID, FaceID                           |\n| Windows          | Windows Hello                             |\n| Cross-platform   | YubiKey, other FIDO2 security keys        |\n\n## Installation\n\n```bash\ncomposer require netresearch/nr-passkeys-be\n```\n\nActivate the extension in the TYPO3 Extension Manager or via CLI:\n\n```bash\nvendor/bin/typo3 extension:activate nr_passkeys_be\n```\n\n## Quick Start\n\nAfter installation, follow these steps:\n\n1. **Review extension settings** — Go to **Admin Tools \u003e Settings \u003e Extension Configuration \u003e nr_passkeys_be** and verify the Relying Party settings (`rpId`, `rpName`, `origin`). The defaults auto-detect from your domain, which works for most single-domain setups.\n\n2. **Open the Passkey Management module** — Navigate to **Admin Tools \u003e Passkey Management**. The Dashboard shows adoption statistics and the Help tab provides a full rollout guide with recovery procedures and FAQ.\n\n3. **Register your own passkey** — Go to **User Settings \u003e Passkeys** and register a passkey to verify the setup works on your device.\n\n4. **Enable enforcement for a pilot group** — On the Dashboard, set a small group (e.g., your admin team) to *Encourage*. Users will see a dismissible banner prompting them to set up a passkey.\n\n5. **Roll out gradually** — Progress through *Encourage* → *Required* → *Enforced* as adoption grows. See the Help tab in the backend module for the complete rollout guide.\n\n\u003e **Full documentation:** [docs.typo3.org/p/netresearch/nr-passkeys-be](https://docs.typo3.org/p/netresearch/nr-passkeys-be/main/en-us/) · [Configuration reference](Documentation/Configuration/Index.rst)\n\n## Passkeys \u0026 MFA\n\nPasskeys are **inherently multi-factor**: they combine *something you have* (your device) with *something you are* (biometric) or *something you know* (device PIN). They are also phishing-resistant — the credential is cryptographically bound to the origin.\n\n**For most TYPO3 backends, passkeys alone are more secure than password + TOTP.** The FIDO Alliance and W3C consider passkeys a stronger replacement for password + OTP. Adding TYPO3's MFA on top is optional defence-in-depth, not a requirement.\n\nConsider keeping MFA enabled alongside passkeys only if:\n- Your security policy explicitly mandates independent factors (e.g., PCI-DSS)\n- Your threat model includes authenticator device compromise\n\nSee the Help tab in **Admin Tools \u003e Passkey Management** for details on MFA coexistence and middleware processing order.\n\n## Configuration\n\nExtension settings are available in **Admin Tools \u003e Settings \u003e Extension Configuration \u003e nr_passkeys_be**:\n\n| Setting | Default | Description |\n|---------|---------|-------------|\n| `rpId` | *(auto-detect)* | Relying Party domain (e.g., `example.com`) |\n| `rpName` | `TYPO3 Backend` | Display name shown during passkey registration |\n| `origin` | *(auto-detect)* | Full origin URL (e.g., `https://example.com`) |\n| `challengeTtlSeconds` | `120` | Challenge token lifetime in seconds |\n| `discoverableLoginEnabled` | `true` | Allow username-less login via resident credentials |\n| `disablePasswordLogin` | `false` | Block password login for users with registered passkeys |\n| `rateLimitMaxAttempts` | `10` | Requests per IP per endpoint before rate limiting |\n| `rateLimitWindowSeconds` | `300` | Rate limit window duration in seconds |\n| `lockoutThreshold` | `5` | Failed login attempts (per IP) before account lockout |\n| `lockoutUserThreshold` | `15` | Failed login attempts (per username, all IPs) before account lockout |\n| `lockoutDurationSeconds` | `900` | Lockout duration in seconds (15 min) |\n| `userVerification` | `required` | WebAuthn user verification requirement |\n| `allowedAlgorithms` | `ES256` | Comma-separated signing algorithms |\n\nSee the [Configuration documentation](Documentation/Configuration/Index.rst) for detailed descriptions of each setting.\n\n## How It Works\n\nThe extension registers a TYPO3 authentication service at priority 80 (above `SaltedPasswordService` at 50). When passkey assertion data is present in the login request, it verifies the WebAuthn assertion. When no passkey data is present, it passes through to the next auth service (standard password login) unless password login is disabled.\n\n### API Endpoints\n\n**Login** (public):\n- `POST /passkeys/login/options` -- Generate authentication challenge\n- `POST /passkeys/login/verify` -- Verify passkey assertion\n\n**Self-Service** (authenticated, AJAX routes):\n- `POST /ajax/passkeys/manage/registration/options` -- Generate registration challenge *\n- `POST /ajax/passkeys/manage/registration/verify` -- Complete passkey registration *\n- `GET /ajax/passkeys/manage/list` -- List own passkeys\n- `POST /ajax/passkeys/manage/rename` -- Rename a passkey label *\n- `POST /ajax/passkeys/manage/remove` -- Remove a passkey *\n\n**Admin** (admin-only, AJAX routes):\n- `GET /ajax/passkeys/admin/list?beUserUid=N` -- List any user's passkeys\n- `POST /ajax/passkeys/admin/remove` -- Revoke a user's passkey *\n- `POST /ajax/passkeys/admin/revoke-all` -- Revoke all passkeys for a user *\n- `POST /ajax/passkeys/admin/unlock` -- Unlock a locked-out user *\n- `POST /ajax/passkeys/admin/update-enforcement` -- Update group enforcement level *\n- `POST /ajax/passkeys/admin/send-reminder` -- Send passkey setup reminder *\n- `POST /ajax/passkeys/admin/clear-nudge` -- Clear active nudge for a user *\n\n**Enforcement** (authenticated, AJAX route):\n- `GET /ajax/passkeys/enforcement/status` -- Get enforcement status for banner\n\n\\* Protected by TYPO3 **Sudo Mode** -- write operations require password re-verification (15 min grant lifetime).\n\n## Documentation\n\n- **Online documentation:** [docs.typo3.org/p/netresearch/nr-passkeys-be](https://docs.typo3.org/p/netresearch/nr-passkeys-be/main/en-us/)\n- **In the backend:** Admin Tools \u003e Passkey Management \u003e Help tab (rollout guide, recovery, FAQ)\n- **Source:** [Documentation/](Documentation/) directory (RST format)\n\n## Development\n\n```bash\ncomposer install\n\n# Code quality\ncomposer ci:test:php:cgl       # Check code style (PER-CS3.0)\ncomposer ci:cgl                # Fix code style\ncomposer ci:test:php:phpstan   # PHPStan level 10\n\n# Tests\ncomposer ci:test:php:unit         # Unit tests\ncomposer ci:test:php:functional   # Functional tests (requires MySQL)\ncomposer ci:test:php:all          # All test suites\ncomposer ci:mutation              # Mutation testing (MSI \u003e= 80%)\n\n# Or use make\nmake ci                           # Run lint + stan + unit + fuzz locally\nmake up                           # Start DDEV with all TYPO3 versions\nmake help                         # Show all available targets\n```\n\n## Security\n\nIf you discover a security vulnerability, please report it responsibly. See [SECURITY.md](SECURITY.md) for details.\n\n## License\n\nGPL-2.0-or-later. See [LICENSE](LICENSE).\n\n---\n\n\u003cp align=\"center\"\u003e\n  Developed and maintained by \u003ca href=\"https://www.netresearch.de/\"\u003eNetresearch DTT GmbH\u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetresearch%2Ft3x-nr-passkeys-be","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnetresearch%2Ft3x-nr-passkeys-be","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetresearch%2Ft3x-nr-passkeys-be/lists"}