PHPackages                             glueful/users - 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. glueful/users

ActiveGlueful-extension[Authentication &amp; Authorization](/categories/authentication)

glueful/users
=============

Users: first-party identity store + account lifecycle for Glueful

v2.3.2(3w ago)0327↑785.7%1MITPHPPHP ^8.3

Since Jun 5Pushed 3w agoCompare

[ Source](https://github.com/glueful/users)[ Packagist](https://packagist.org/packages/glueful/users)[ RSS](/packages/glueful-users/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (6)Versions (14)Used By (1)

Users (Identity &amp; Accounts) Extension for Glueful
=====================================================

[](#users-identity--accounts-extension-for-glueful)

Overview
--------

[](#overview)

Users is the **first-party identity store and account-lifecycle extension** for Glueful. It provides the concrete, swappable user store that sits behind Glueful's core authentication contracts — the `users` and `profiles` tables, credential verification, email verification / OTP, password reset, and optional email-PIN two-factor authentication.

Glueful core is provider-agnostic and ships **no** user store of its own. It authenticates through the `UserProviderInterface` contract and binds a fail-closed `NullUserProvider` by default — so **without a user store enabled, authentication is disabled by design**. This extension is that store. The Glueful **api-skeleton enables it by default**.

> Swap-friendly by design: any package that implements `UserProviderInterface` can replace this one. Users is simply the official, batteries-included implementation.

Features
--------

[](#features)

- **Provider-agnostic identity seam**: implements core's `UserProviderInterface` (lookup + credential verification, returning a canonical `UserIdentity`)
- **Account store**: `users` + `profiles` tables with UUID principals, soft-deletes, and unique constraints
- **Extensible from your app**: add custom profile columns, enrich the login response, or contribute identity claims without forking the extension (see [Extending Users](#extending-users))
- **Email verification / OTP**: send, verify, and resend one-time codes
- **Password reset**: forgot-password -&gt; verify OTP with `purpose=password_reset` -&gt; reset-password with a single-use reset token
- **Email-PIN two-factor authentication**: enroll, verify, and disable 2FA behind core's `TwoFactorServiceInterface` (opt-in via `auth.two_factor.enabled`)
- **SSO provisioning helpers**: `findOrCreateFromSaml()` / `findOrCreateFromLdap()` on the repository
- **Ordered migrations**: schema runs at `IDENTITY` priority (before app/dependent extensions), source-tracked as `glueful/users`
- **Admin CLI**: password reset and 2FA management commands

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

[](#installation)

### Installation (Recommended)

[](#installation-recommended)

**Install via Composer**

```
composer require glueful/users

# Rebuild the extensions cache after adding new packages
php glueful extensions:cache
```

Composer discovers packages of type `glueful-extension`, but **installing does not auto-enable** them — the provider must be added to `config/extensions.php`'s `enabled` allow-list. The CLI does that for you:

```
# Enable (adds the provider FQCN to config/extensions.php + recompiles the cache)
php glueful extensions:enable users

# Disable (removes it) — note: disabling leaves core auth on the fail-closed NullUserProvider
php glueful extensions:disable users
```

In production, manage the `enabled` list in config and run `php glueful extensions:cache` in your deploy step.

Run database migrations to create the `users` and `profiles` tables:

```
php glueful migrate:run
```

### Email delivery dependency

[](#email-delivery-dependency)

The email-driven flows (verify-email, forgot-password, and the 2FA PIN) send through Glueful's notification system on the **`email`** channel. Users depends only on that channel *capability*, not on a specific extension — install any extension that registers an `email` channel. The official one is **`glueful/email-notification`**:

```
composer require glueful/email-notification
php glueful extensions:enable email-notification
```

If no `email` channel is registered, those sends return a clear `email_provider_not_configured` result (and are logged) instead of delivering — the rest of the account store still works.

### Local Development Installation

[](#local-development-installation)

To develop the extension locally, register it as a Composer **path repository** in your app's `composer.json`, then require and enable it:

```
// composer.json
"repositories": [
    { "type": "path", "url": "extensions/users", "options": { "symlink": true } }
]
```

```
composer require glueful/users:@dev
php glueful extensions:enable users
```

Entries in `config/extensions.php` are plain string FQCNs (no `::class`) — prefer `extensions:enable` over editing by hand.

Run the migrations to create the necessary database tables:

```
php glueful migrate:run
```

### Verify Installation

[](#verify-installation)

Check status and details:

```
php glueful extensions:list
php glueful extensions:info users
php glueful extensions:diagnose
```

Post-install checklist:

- Run migrations (if not auto-run): `php glueful migrate:run`
- Enable an `email` channel for verification/reset/2FA emails (see above)
- Confirm core auth resolves the provider: a username/password `POST /auth/login` should succeed for a valid user
- Rebuild cache after Composer operations: `php glueful extensions:cache`

### Quick Start

[](#quick-start)

The account-lifecycle endpoints are mounted under `/auth`. Example: the forgot-password → reset-password flow. Replace placeholders before running:

- `API_BASE` with your base URL (e.g., )
- `USER_EMAIL` with an existing user's email

```
API_BASE=http://localhost:8000
USER_EMAIL="user@example.com"

# 1) Request a reset code (emailed via the 'email' channel)
curl -s -X POST "$API_BASE/auth/forgot-password" \
  -H "Content-Type: application/json" \
  -d "{\"email\": \"$USER_EMAIL\"}" | jq .

# 2) Verify the emailed code
curl -s -X POST "$API_BASE/auth/verify-otp" \
  -H "Content-Type: application/json" \
  -d "{\"email\": \"$USER_EMAIL\", \"otp\": \"\"}" | jq .

# 3) Set the new password (email + new password; the code is verified in step 2)
curl -s -X POST "$API_BASE/auth/reset-password" \
  -H "Content-Type: application/json" \
  -d "{\"email\": \"$USER_EMAIL\", \"password\": \"\"}" | jq .
```

### Quick Start (PHP)

[](#quick-start-php)

The provider backs core login; you typically use it indirectly via `POST /auth/login`. To work with it programmatically:

```
