Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Oauth2 Server Password Client Laravel Package

spomky-labs/oauth2-server-password-client

A password-grant client extension for the Spomky-Labs OAuth2 server library, adding support for the resource owner password credentials flow so your authorization server can issue tokens from a username and password.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is an add-on to spomky-labs/oauth2-server that supplies a Password Client — the server-side client type/credential set used by the Resource Owner Password Credentials grant. It is not a standalone server; it plugs into the parent package's server pipeline.

First, be aware of the health signals: zero stars, zero dependents, and the parent spomky-labs/oauth2-server has been archived and superseded by league/oauth2-server. Treat this as legacy code. If you are starting greenfield work, jump straight to league/oauth2-server and its PasswordGrant. If you are inheriting a project that already depends on this, the walkthrough below gets you productive quickly.

Minimal install:

composer require spomky-labs/oauth2-server-password-client

First look:

  1. src/ — expect a small surface: a PasswordClient (or similarly named) class implementing the parent package's ClientInterface, plus possibly a factory/manager.
  2. composer.json — confirm the parent-version constraint (spomky-labs/oauth2-server) it was written against. That constraint is the single best clue to whether it will work with the version already in your lockfile.
  3. The parent package's README and Server usage docs — this add-on makes no sense in isolation.

First use case — wiring the password client into a server:

use SpomkyLabs\OAuth2Server\PasswordClient\PasswordClient;

$client = new PasswordClient(
    $clientId,        // e.g. 'mobile-app'
    $clientSecret,    // hashed or plain depending on parent config
    $redirectUris,    // array; often empty for password grant
    $allowedGrantTypes // ['password']
);

$server->setClient($client); // or addClient()/getClients() depending on parent API

Then the token endpoint receives grant_type=password&username=...&password=... and delegates to your UserRepositoryInterface.

Implementation Patterns

Register the client in a manager, not ad-hoc per request. The parent package usually exposes a ClientManager/ClientManagerInterface. Populate it in a service provider so controllers stay thin:

$this->app->singleton(ClientManagerInterface::class, function ($app) {
    $manager = new ClientManager($app->make(StorageInterface::class));
    $manager->addClient(new PasswordClient(/* ... */));
    return $manager;
});

Pair with a storage adapter. The password client itself only describes who is authenticating. You still need a ClientStorage/ClientManager and a UserRepository for the resource-owner lookup. Keep these two concerns separate — the client knows nothing about users.

One client per application/tenant. The password grant is typically used by first-party mobile or CLI apps, not third parties. Model each app as its own client ID with allowedGrantTypes = ['password']. Do not reuse the same client ID across grant types; scope creep in grants is a common audit finding.

Integration with Laravel routing. A single controller action is enough:

Route::post('/oauth/token', function (Server $server, Request $request) {
    $response = $server->handleTokenRequest(
        \OAuth2\HttpFoundationBridge\Request::createFromGlobals()
    );
    return $response->send();
});

Because the parent package predates PSR-7 ubiquity, expect an adapter layer (HttpFoundation bridge) rather than native PSR-7 responses.

Workflow: hash the secret at rest. Store the client secret hashed (password_hash) and let the parent's client validation compare it. The password client constructor generally accepts the already-stored value; validation happens in the grant. If the parent version you're on expects plaintext, isolate that in a single adapter — never store plaintext in your DB.

Testing pattern. Drive the token endpoint with feature tests using real HTTP:

$this->postJson('/oauth/token', [
    'grant_type' => 'password',
    'username'   => '[email protected]',
    'password'   => 'correct-horse',
    'client_id'  => 'mobile-app',
    'client_secret' => '...',
])->assertJsonStructure(['access_token', 'token_type', 'expires_in']);

This exercises the client wiring, the storage adapter, and the user repository in one shot — the fastest way to validate a legacy OAuth setup.

Gotchas and Tips

Archived dependency, not archived add-on. The real risk isn't this tiny package — it's that spomky-labs/oauth2-server is no longer maintained. Security fixes land in league/oauth2-server only. Budget a migration: the grant type classes are conceptually equivalent (PasswordClient → PasswordGrant + ClientRepository), but constructor signatures differ. Do not patch security-sensitive logic in an unmaintained layer.

Grant-type mismatch is silent-ish. If allowedGrantTypes on the client omits password, the grant rejects with invalid_grant/unauthorized_client rather than a configuration error. When debugging, log the resolved client's allowed grants before the server handles the request.

Client authentication method matters. The parent version may default to HTTP Basic client auth or require client_id/client_secret in the body. Password-grant mobile clients often cannot easily set Basic auth. Pin the method explicitly and add a test for both — this is the most common "works in Postman, fails in app" cause.

Password grant is deprecated in OAuth 2.1. Even internally, prefer Authorization Code + PKCE for anything with a browser. Use the password grant only for first-party native apps where the app is the resource owner's client. If you can avoid it, do.

Don't leak user existence. The parent may return invalid_grant for bad passwords and invalid_request/invalid_grant inconsistently for unknown users. Normalize both to the same error to avoid username enumeration. If the user lookup throws, catch and translate it before it bubbles into a 500.

Composer constraint drift. Because this package pins an old parent version, a broad composer update can either lock the parent in place or fail resolution. Run composer why-not spomky-labs/oauth2-server when upgrading anything — it will show exactly which package is holding you back.

Extension points are narrow. The package is a thin value object around the parent's client interface. Custom behavior (scopes per client, TTL overrides) belongs in your ClientManager/storage implementation, not by subclassing the password client. If you find yourself extending it, that's a signal to migrate.

Token storage and revocation. This package says nothing about token storage — that lives in the parent plus your AccessTokenStorage. Ensure you have revocation support before shipping; a legacy parent without revocation hooks is a compliance gap.

Debugging checklist when a token request fails: (1) is the client resolvable by client_id? (2) does allowedGrantTypes include password? (3) does the user repository find the username? (4) is the hashed secret comparison using the same algorithm as storage? (5) is the request body parsed (form-encoded, not JSON)? Answer those five in order and you'll solve ~90% of failures.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings