assegaiphp / auth
Authentication strategies for AssegaiPHP and standalone PHP applications.
Requires
- php: >=8.3
- assegaiphp/attributes: ^1.0
- firebase/php-jwt: ^7.0
Requires (Dev)
- pestphp/pest: ^3.7
- phpstan/phpstan: ^2.1
README
Authentication strategies for AssegaiPHP and standalone PHP applications.
Overview
assegaiphp/auth is a small authentication package built around focused strategies instead of a full auth framework.
Today the package ships with:
SessionAuthStrategyfor session-backed login stateJwtAuthStrategyfor stateless JWT authenticationOAuth2AuthStrategyfor OAuth 2.0 authorization-code login flowsGitHubOAuthProvideras the first ready-to-use OAuth provider adapter
The package is intentionally narrow. It helps you:
- authenticate a known user object
- issue session or JWT auth state
- begin and complete OAuth 2.0 login flows
- hand a resolved OAuth user into session or JWT auth
It does not currently provide:
- user lookup or persistence
- registration or password reset flows
- refresh token rotation
- OAuth route/controllers for you
- OAuth guard wiring
- multiple polished provider adapters beyond GitHub
You still own the application flow around it: loading users, choosing when to authenticate, defining routes, and deciding what to do after login succeeds.
Installation
composer require assegaiphp/auth
Session Authentication
Use SessionAuthStrategy when you want the authenticated user stored in $_SESSION.
<?php use Assegai\Auth\Strategies\SessionAuthStrategy; $user = (object) [ 'id' => 7, 'email' => 'user@example.com', 'password' => password_hash('secret', PASSWORD_DEFAULT), 'name' => 'Test User', ]; $strategy = new SessionAuthStrategy([ 'user' => $user, 'session_name' => 'blog_api', 'session_lifetime' => '+1 hour', ]); if ($strategy->authenticate([ 'email' => 'user@example.com', 'password' => 'secret', ])) { $currentUser = $strategy->getUser(); }
Session behavior
On successful authentication the strategy:
- starts a session if needed
- clones the configured user object
- removes the password field from that clone
- stores the sanitized user in
$_SESSION['user']
Trusted session handoff
This is useful after an OAuth callback, when the user has already been verified by the provider and you just want to establish a local session.
$strategy->establishAuthenticatedUser((object) [ 'id' => 42, 'email' => 'oauth@example.com', 'name' => 'OAuth User', ]);
JWT Authentication
Use JwtAuthStrategy when you want to issue a JWT and later validate it from a bearer token or from a token you pass into the strategy config.
<?php use Assegai\Auth\Strategies\JwtAuthStrategy; $user = (object) [ 'id' => 7, 'email' => 'user@example.com', 'password' => password_hash('secret', PASSWORD_DEFAULT), 'roles' => ['author'], 'name' => 'Test User', ]; $strategy = new JwtAuthStrategy([ 'user' => $user, 'secret_key' => 'replace-with-a-long-random-secret-key', 'issuer' => 'blog-api', 'audience' => 'blog-api-clients', 'token_lifetime' => '+1 hour', ]); if ($strategy->authenticate([ 'email' => 'user@example.com', 'password' => 'secret', ])) { $token = $strategy->getToken(); }
JWT behavior
On successful authentication the strategy creates a token payload with:
sub- the configured username field
iatexp- optional
iss - optional
aud - optional
roles - optional
name
isAuthenticated() validates either:
- the token generated by the strategy, or
- the
Authorization: Bearer ...header when one is present
Trusted JWT handoff
This is useful after an OAuth callback when you want to mint a local API token for a provider-authenticated user.
$token = $strategy->issueTokenForUser((object) [ 'id' => 42, 'email' => 'oauth@example.com', 'name' => 'OAuth User', 'roles' => ['member'], ]);
OAuth 2.0
Use OAuth2AuthStrategy when you need an authorization-code flow such as "Sign in with GitHub".
Unlike the session and JWT strategies, OAuth is a redirect-based flow, so it does not implement AuthStrategyInterface.
The OAuth flow is split into two steps:
- build the authorization request and redirect the user
- handle the callback and establish local auth state
GitHub example
<?php use Assegai\Auth\OAuth\OAuth2AuthStrategy; use Assegai\Auth\OAuth\Providers\GitHubOAuthProvider; use Assegai\Auth\OAuth\State\SessionOAuthStateStore; use Assegai\Auth\Strategies\SessionAuthStrategy; $sessionStrategy = new SessionAuthStrategy([ 'user' => (object) [], 'session_name' => 'blog_api', ]); $oauth = new OAuth2AuthStrategy( provider: new GitHubOAuthProvider(), config: GitHubOAuthProvider::defaultConfig( clientId: 'your-github-client-id', clientSecret: 'your-github-client-secret', redirectUri: 'https://example.com/auth/github/callback', ), stateStore: new SessionOAuthStateStore(), sessionStrategy: $sessionStrategy, ); $request = $oauth->beginLogin(); header('Location: ' . $request->url); exit;
Handling the callback
<?php use Assegai\Auth\OAuth\OAuth2AuthStrategy; use Assegai\Auth\OAuth\Providers\GitHubOAuthProvider; use Assegai\Auth\OAuth\State\SessionOAuthStateStore; use Assegai\Auth\Strategies\JwtAuthStrategy; use Assegai\Auth\Strategies\SessionAuthStrategy; $sessionStrategy = new SessionAuthStrategy([ 'user' => (object) [], ]); $jwtStrategy = new JwtAuthStrategy([ 'secret_key' => 'replace-with-a-long-random-secret-key', 'user' => (object) [ 'email' => 'placeholder@example.com', 'password' => password_hash('placeholder', PASSWORD_DEFAULT), ], ]); $oauth = new OAuth2AuthStrategy( provider: new GitHubOAuthProvider(), config: GitHubOAuthProvider::defaultConfig( clientId: 'your-github-client-id', clientSecret: 'your-github-client-secret', redirectUri: 'https://example.com/auth/github/callback', ), stateStore: new SessionOAuthStateStore(), sessionStrategy: $sessionStrategy, jwtStrategy: $jwtStrategy, ); $result = $oauth->handleCallback($_GET); // $result->user // $result->profile // $result->sessionEstablished // $result->jwtToken
What OAuth2AuthStrategy does
OAuth2AuthStrategy:
- generates a secure state value
- generates PKCE verifier/challenge by default
- stores the state in the configured
OAuthStateStoreInterface - exchanges the callback code for tokens
- fetches the provider profile
- resolves a local user object
- optionally hands that user into session and/or JWT auth
Current OAuth boundaries
What is ready today:
- generic OAuth provider interface
- PKCE-enabled authorization code flow
- session-backed state store
- GitHub provider adapter
- local session/JWT handoff
What you still provide:
- the login route
- the callback route
- any persistence or lookup logic for provider users
- redirects or API responses after login
Custom OAuth providers
If GitHub is not the right provider, implement OAuthProviderInterface.
You need to provide:
- a provider name
- how to build the authorization URL
- how to exchange a code for tokens
- how to fetch the provider user profile
You can also extend AbstractOAuthProvider to reuse the common HTTP and URL-building helpers.
Using the strategy interface
If the built-in session or JWT strategies are not the right fit, implement AuthStrategyInterface.
<?php use Assegai\Auth\Interfaces\AuthStrategyInterface; class CustomAuthStrategy implements AuthStrategyInterface { public function authenticate(array $credentials): bool { return false; } public function isAuthenticated(): bool { return false; } public function getUser(): ?object { return null; } public function logout(): void { } }
Pairing with Assegai Core
In an Assegai app, a common pattern is:
- load a user from your repository or service
- pass that user into a session or JWT strategy, or complete an OAuth callback
- establish local auth state
- read authentication state from your guards, providers, or handlers
This package handles the strategy side of that flow. The application still owns the surrounding request flow.
API surface
AuthStrategyInterface
| Method | Description |
|---|---|
authenticate(array $credentials): bool |
Validates credentials and establishes authentication state. |
isAuthenticated(): bool |
Checks whether the current strategy considers the request authenticated. |
getUser(): ?object |
Returns the authenticated user or token-backed user payload. |
logout(): void |
Clears the current authentication state. |
SessionAuthStrategy
| Method | Description |
|---|---|
establishAuthenticatedUser(object $user): void |
Establishes trusted session auth without re-checking credentials. |
JwtAuthStrategy
| Method | Description |
|---|---|
getToken(): string |
Returns the last generated JWT. |
getDecoded(): \stdClass |
Decodes the current JWT with the configured key and algorithm. |
issueTokenForUser(object $user): string |
Issues a JWT for a trusted user object without re-checking credentials. |
OAuth2AuthStrategy
| Method | Description |
|---|---|
beginLogin(): OAuthAuthorizationRequest |
Builds the provider redirect request and persists state/PKCE data. |
handleCallback(array $callback): OAuthLoginResult |
Validates the callback, resolves the provider user, and optionally establishes local auth state. |
Running tests
vendor/bin/pest
License
MIT. See LICENSE.