PHPackages                             xefi/laravel-passkey-api - 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. xefi/laravel-passkey-api

ActiveLibrary

xefi/laravel-passkey-api
========================

A Laravel package for passkey authentication apis

10[1 PRs](https://github.com/xefi/laravel-passkey-api/pulls)PHP

Since Mar 25Pushed 1mo agoCompare

[ Source](https://github.com/xefi/laravel-passkey-api)[ Packagist](https://packagist.org/packages/xefi/laravel-passkey-api)[ RSS](/packages/xefi-laravel-passkey-api/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

Laravel Passkey API
===================

[](#laravel-passkey-api)

A Laravel package for passkey (WebAuthn) authentication.

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

[](#requirements)

- PHP 8.1+ (Note: Laravel 11/12/13 may require newer PHP versions depending on the framework release)
- Laravel 10.x, 11.x, 12.x, or 13.x
- `spomky-labs/cbor-php`: for CBOR decoding
- `web-auth/cose-lib`: for COSE key handling
- `openssl` PHP extension

Tip

[Laravel Sanctum](https://laravel.com/docs/sanctum) is suggested if you want to use the default token-based authentication session, but it is not a hard requirement.

Installation
------------

[](#installation)

Install the package via Composer:

```
composer require xefi/laravel-passkey-api
```

The package will automatically register its service provider through Laravel's package auto-discovery.

### Database Setup

[](#database-setup)

Publish and run the migrations:

```
php artisan vendor:publish --tag=passkey-migrations
php artisan migrate
```

This will create a `passkeys` table to store passkey credentials.

### Configuration

[](#configuration)

Optionally publish the configuration file:

```
php artisan vendor:publish --tag=passkey-config
```

This creates `config/passkey.php` where you can customize:

- `enabled`: Enable/disable the passkey package (default: `true`, env: `PASSKEY_ENABLED`)
- `timeout`: Passkey operation timeout in milliseconds (default: `60000`, env: `PASSKEY_TIMEOUT`)
- `challenge_length`: Length of the challenge in bytes (default: `32`, env: `PASSKEY_CHALLENGE_LENGTH`)
- `user_model`: The User model class (default: `App\Models\User`, env: `PASSKEY_USER_MODEL`)
- `middleware`: The middleware to apply to passkey routes. You can customize the `auth` middleware (default: `auth:sanctum`).

### User Model Setup

[](#user-model-setup)

Add the `HasPasskeys` trait to your User model:

```
use Xefi\LaravelPasskey\Traits\HasPasskeys;

class User extends Authenticatable
{
    use HasPasskeys;

    // ... existing code
}
```

API Endpoints
-------------

[](#api-endpoints)

The package provides several API endpoints for passkey management and authentication:

### Passkey Management (require authentication)

[](#passkey-management-require-authentication)

#### List Passkeys

[](#list-passkeys)

```
GET /api/passkeys
Authorization: Bearer
```

Returns a list of passkeys registered for the authenticated user.

#### Get Registration Options

[](#get-registration-options)

```
POST /api/passkeys/register/options
Authorization: Bearer
Content-Type: application/json
```

Returns options needed to create a new passkey credential.

**Request Body:**

```
{
  "app_name": "My Application",
  "app_url": "https://example.com"
}
```

**Response:**

```
{
  "challenge": "base64-encoded-challenge",
  "rp": {
    "name": "My Application",
    "id": "example.com"
  },
  "user": {
    "id": "base64-encoded-user-id",
    "name": "user@example.com",
    "displayName": "John Doe"
  },
  "pubKeyCredParams": [
    {"type": "public-key", "alg": -7},
    {"type": "public-key", "alg": -257}
  ],
  "timeout": 600000,
  "attestation": "none",
  "authenticatorSelection": {
    "residentKey": "preferred",
    "userVerification": "preferred"
  }
}
```

#### Register Passkey

[](#register-passkey)

```
POST /api/passkeys/register
Authorization: Bearer
Content-Type: application/json
```

Registers a new passkey credential and persists it to the database.

**Request Body:**

```
{
  "label": "My Security Key",
  "id": "credential-id",
  "rawId": "raw-credential-id",
  "type": "public-key",
  "response": {
    "clientDataJSON": "base64-encoded-client-data",
    "attestationObject": "base64-encoded-attestation"
  }
}
```

**Response:**

```
{
  "passkey": {
    "id": 1,
    "label": "My Security Key",
    "credential_id": "base64-encoded-credential-id",
    "created_at": "2024-01-19T08:50:00.000000Z"
  }
}
```

### Authentication Flow (public)

[](#authentication-flow-public)

#### Get Verification Options

[](#get-verification-options)

```
POST /api/passkeys/verify/options
Content-Type: application/json
```

Returns options needed to verify a passkey credential (challenge and allowed credentials).

**Request Body:**

```
{
  "credential_id": "base64-encoded-credential-id"
}
```

**Response:**

```
{
  "challenge": "base64-encoded-challenge",
  "allowCredentials": [
    {
      "id": "base64-encoded-credential-id",
      "type": "public-key"
    }
  ],
  "timeout": 60000,
  "userVerification": "preferred"
}
```

#### Verify Passkey

[](#verify-passkey)

```
POST /api/passkeys/verify
Content-Type: application/json
```

Verifies a passkey authentication attempt without creating a session. Useful for MFA or re-authentication.

**Request Body:**

```
{
  "id": "credential-id",
  "rawId": "raw-credential-id",
  "type": "public-key",
  "response": {
    "clientDataJSON": "base64-encoded-client-data",
    "authenticatorData": "base64-encoded-auth-data",
    "signature": "base64-encoded-signature"
  }
}
```

**Response:**

```
{
  "user": {
    "id": 1
  },
  "passkey": {
    "id": 1
  }
}
```

#### Authenticate (Login)

[](#authenticate-login)

```
POST /api/passkeys/login
Content-Type: application/json
```

Authenticates a user via passkey and returns a Sanctum token.

**Request Body:** Same as **Verify Passkey**.

**Response:**

```
{
  "user": {
    "id": 1,
    "name": "User Name",
    "email": "user@example.com"
  },
  "token": "sanctum-plain-text-token"
}
```

Usage
-----

[](#usage)

After installation, the package routes will be automatically registered. You can verify the routes are available:

```
php artisan route:list --path=passkeys
```

### Accessing User Passkeys

[](#accessing-user-passkeys)

You can access a user's passkeys through the relationship:

```
$user = User::find(1);
$passkeys = $user->passkeys;

foreach ($passkeys as $passkey) {
    echo $passkey->label;
    echo $passkey->created_at;
}
```

Testing
-------

[](#testing)

This package comes with a fully isolated Docker environment to ensure tests run consistently without requiring a local PHP installation.

To run the test suite, simply use the provided `make` commands:

```
# Run the test suite
make test

# Run tests and generate an HTML code coverage report (in the /coverage directory)
make test-coverage

# Open a bash shell inside the PHP container for debugging
make bash
```

Note

The `make test` and `make test-coverage` commands will automatically build the Docker image and install Composer dependencies if they are missing. You can force this installation step manually using `make setup`.

Architecture Pattern
--------------------

[](#architecture-pattern)

This library follows a clean, service-oriented architecture to maintain the **Single Responsibility Principle**:

 ```
flowchart TD
    HTTP([HTTP Request])

    HTTP --> Route

    Route["PasskeyRoute\n(api.php)"]
    Route --> Validation

    Validation["FormRequest Validation\nRegisterRequest / VerifyRequest"]
    Validation --> Controller

    Controller["PasskeyController\n(Thin Layer)\n— Throws Exceptions"]
    Service["WebAuthn\n(Business Logic)\n— Parsing CBOR\n— Verify COSE / OpenSSL\n— Data Extraction"]

    Service --> Controller
    Controller --> Model

    Model["Passkey Model\n(Persistence)"]
    Model --> User

    User["User Model\n(App\\Models\\User)\nvia HasPasskeys Trait"]
```

      Loading Note

The controller uses Laravel's exception handling mechanism. Errors are thrown as exceptions (`AuthenticationException`, `PasskeyNotFoundException`, `UserNotFoundException`, etc.) rather than returning JSON error responses directly.

Typical Sequence Flow
---------------------

[](#typical-sequence-flow)

Here is the typical sequence of interactions between the Client (Browser), the Server (API), and the Authenticator (Security Key, TouchID, etc.):

 ```
sequenceDiagram
    actor User
    participant Browser as Browser (JS)
    participant Server as Server (API)
    participant Auth as Authenticator

    Note over User,Auth: 1. Initial Login (App Logic)
    User->>Browser: Login
    Browser->>Server: POST /login
    Server-->>Browser: Sanctum Token

    Note over User,Auth: 2. Register Passkey
    User->>Browser: Register
    Browser->>Server: POST /api/passkeys/register/options
    Server-->>Browser: Registration Options

    Browser->>Auth: navigator.credentials.create()
    Note over Auth: 3. Fingerprint / Biometric
    Auth-->>User: Prompt
    User-->>Auth: Confirm
    Note over Auth: 4. Attestation
    Auth-->>Browser: Attestation Object

    Browser->>Server: POST /api/passkeys/register
    Server-->>Browser: Success

    Note over User,Auth: 5. Authentication (Login)
    User->>Browser: Login with Passkey
    Browser->>Server: POST /api/passkeys/verify/options
    Server-->>Browser: Authentication Options

    Browser->>Auth: navigator.credentials.get()
    Note over Auth: 6. Fingerprint / Biometric
    Auth-->>User: Prompt
    User-->>Auth: Confirm
    Note over Auth: 7. Assertion
    Auth-->>Browser: Assertion Object

    Browser->>Server: POST /api/passkeys/login
    Server-->>Browser: NEW Sanctum Token
```

      Loading

###  Health Score

20

—

LowBetter than 14% of packages

Maintenance60

Regular maintenance activity

Popularity2

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 66.7% 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.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/12382966?v=4)[Gautier DELEGLISE](/maintainers/GautierDele)[@GautierDele](https://github.com/GautierDele)

---

Top Contributors

[![faro-thomyris](https://avatars.githubusercontent.com/u/76995624?v=4)](https://github.com/faro-thomyris "faro-thomyris (2 commits)")[![f-rosito](https://avatars.githubusercontent.com/u/178981093?v=4)](https://github.com/f-rosito "f-rosito (1 commits)")

### Embed Badge

![Health badge](/badges/xefi-laravel-passkey-api/health.svg)

```
[![Health](https://phpackages.com/badges/xefi-laravel-passkey-api/health.svg)](https://phpackages.com/packages/xefi-laravel-passkey-api)
```

PHPackages © 2026

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