popphp/pop-auth

Pop Auth Component for Pop PHP Framework

Maintainers

Package info

github.com/popphp/pop-auth

pkg:composer/popphp/pop-auth

Transparency log

Statistics

Installs: 8 240

Dependents: 1

Suggesters: 0

Stars: 5

Open Issues: 0

5.0.3 2026-08-23 16:16 UTC

README

Build Status Coverage Status

Join the chat at https://discord.gg/TZjgT74U7E

Overview

pop-auth provides adapters to authenticate users via different authentication sources. The adapters share the same interface and are interchangeable. The available adapters are:

  • File
  • JWT

pop-auth is a component of the Pop PHP Framework.

Database-backed authentication (matching a username/password against a Pop\Db\Record-backed table) has moved to the pop-db component, in favor of a tighter coupling with the DB layer it depends on. See pop-db's documentation for the replacement.

Remote/delegated authentication (forwarding credentials to a remote HTTP endpoint and checking the response) is no longer a dedicated adapter here — use pop-http's Client and Auth classes directly.

Install

Install pop-auth using Composer.

composer require popphp/pop-auth

Or, require it in your composer.json file

"require": {
    "popphp/pop-auth" : "^5.0.0"
}

Top

Quickstart

To verify an authentication attempt, create a new auth object pointed at its authentication source. From there, you can attempt to call the authenticate() with a username and password.

use Pop\Auth;

$auth = new Auth\File('/path/to/.htmyauth');

if ($auth->authenticate('admin', 'password')) {
    // User is authenticated
} else {
    // Handle failed authentication attempt
}

If you need to reference the same authentication attempt result at a later time in the application, you can call isAuthenticated():

var_dump($auth->isAuthenticated()); // Returns bool

Top

Handling Exceptions

authenticate() returning 0 means the credentials were checked and didn't match — that's a normal, expected outcome, not an error. It can also throw Pop\Auth\Exception, but only when the adapter can't perform the check at all: a missing or unreadable file, or malformed/unusable key material for the JWT adapter. Wrap authenticate() in a try/catch to handle both cases:

use Pop\Auth;

$auth = new Auth\File('/path/to/.htmyauth');

try {
    if ($auth->authenticate('admin', 'password')) {
        // User is authenticated
    } else {
        // Credentials didn't match
    }
} catch (Auth\Exception $e) {
    // The adapter couldn't perform the check at all
}

Top

Using a File

Using the file adapter, you need to create a file containing a colon-delimited list of usernames and passwords or, preferably, password hashes:

testuser1:PASSWORD_HASH1
testuser2:PASSWORD_HASH2
testuser3:PASSWORD_HASH3
use Pop\Auth;

$auth = new Auth\File('/path/to/.htmyauth');
$auth->authenticate('testuser1', 'password'); // Returns int

if ($auth->isAuthenticated()) { } // Returns bool

The file adapter also supports realm-scoped entries and a custom field delimiter. When a realm is set, matching lines must have 3 fields (username:realm:hash) with both the username and the realm matching:

testuser1:example.com:PASSWORD_HASH1
testuser2:example.com:PASSWORD_HASH2
use Pop\Auth;

$auth = new Auth\File('/path/to/.htmyauth', 'example.com');
$auth->authenticate('testuser1', 'password'); // Returns int

A different delimiter can be set as the third constructor argument, e.g. new Auth\File('/path/to/.htmyauth', 'example.com', '|') for pipe-delimited entries.

Top

Using a JWT

Using the JWT adapter, you authenticate a bearer token by verifying its signature and claims — there's no network call and no stored username/password, just the token itself and the key material to check it against.

The algorithm is fixed at construction and is never read from the token — pass the shared secret for HS256, or a PEM-encoded public key for RS256/ES256:

use Pop\Auth\Jwt;

$auth = new Jwt('HS256', $secret);
$auth->authenticate($token); // Returns int

if ($auth->isAuthenticated()) { } // Returns bool
use Pop\Auth\Jwt;

$auth = new Jwt('RS256', $publicKeyPem);
$auth->authenticate($token); // Returns int

exp and nbf claims, when present on the token, are always checked (with an optional leeway, in seconds, to absorb clock skew between issuer and verifier). aud and iss are opt-in — only checked if you configure them:

use Pop\Auth\Jwt;

$auth = new Jwt('HS256', $secret);
$auth->setAudience('my-api')
    ->setIssuer('https://auth.example.com')
    ->setLeeway(30);

$auth->authenticate($token); // Returns int

Top

Getting the User

The JWT adapter has a method that allows you to get the decoded claims from a successfully verified token. That method is getUser():

use Pop\Auth\Jwt;

$auth = new Jwt('HS256', $secret);
$auth->authenticate($token); // Returns int

if ($auth->isAuthenticated()) {
    $claims = $auth->getUser();
}

This allows you access to the token's claims without decoding it yourself.

Top

Rehashing Passwords

After a successful authentication, you can check whether the stored hash should be upgraded (e.g. it was stored as plaintext, or was hashed at a now-outdated cost):

use Pop\Auth;

$auth = new Auth\File('/path/to/.htmyauth');
$auth->authenticate('admin', 'password');

if ($auth->isAuthenticated() && $auth->needsRehash()) {
    $newHash = password_hash('password', PASSWORD_DEFAULT);
    // persist $newHash into the file/database yourself — pop-auth never writes to storage
}

This is only meaningful for the File adapter, since it's the one that compares a submitted password against a stored hash. The JWT adapter verifies a signature instead of a hash — needsRehash() is always false on it.

Top