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 Laravel Package

splash/oauth2

Splash OAuth2 brings OAuth2 authentication to Laravel/PHP applications, simplifying secure token handling, authorization flows, and API integrations. It offers a clean, framework-friendly way to protect routes and connect services with standard OAuth2 providers.

View on GitHub
Deep Wiki
Context7

Getting Started

This package's adoption is essentially zero — 0 stars, 0 dependents, GitLab-hosted. That means there is no tutorial, no blog post, and no Stack Overflow corpus to lean on. The source is the documentation, so budget the first hour to read src/, the service provider, and the published config before touching your app.

Minimal setup

composer require splash/oauth2
php artisan vendor:publish --provider="Splash\Oauth2\Oauth2ServiceProvider"
php artisan migrate

Then immediately inventory what you got:

cat vendor/splash/oauth2/composer.json          # PHP + Laravel constraints
find vendor/splash/oauth2/src -name "*.php"      # actual surface area
cat config/oauth2.php                            # the real API reference
ls database/migrations/*oauth*                   # tables it creates

The config file is the map: it tells you what client/token/scope tables exist, what grant types are enabled, what the default token lifetime and refresh-token lifetime are, and which middleware aliases get registered. Cross-reference it against the service provider — anything the provider registers and the config doesn’t expose is a package you’ll be editing in a fork.

First use case — protect one route with one client. Pick the client-credentials grant: no redirect flow, no consent screen, no user table involvement. Insert a client row manually (or via tinker), hit POST /oauth/token with grant_type=client_credentials, get a bearer token back, and guard a single Route::get('/ping', ...)->middleware('auth.oauth'). Confirm the 401 → token → 200 loop end-to-end before wiring any real endpoint. That single loop validates that the middleware alias, the token table, and the config line up — and it’s the fastest way to discover if the package is even installable against your Laravel version.

Implementation Patterns

Treat grant types as separate subsystems. The package ships three: authorization code, client credentials, and password. They share token storage but not much else, and each fails differently. Adopt them in order of least-risk:

  1. Client credentials for machine-to-machine (internal services, cron jobs). No user, no redirect, no refresh — just a client secret and a token endpoint. Ship this first.
  2. Authorization code for third-party web apps acting on behalf of a user. This is the one that needs the most careful review: redirect URI allowlisting, state handling, PKCE (verify whether it's enforced or just supported), and code expiry. Read the controller code yourself — this is where OAuth2 servers get their bugs.
  3. Password grant — only if you already had it. It’s deprecated in OAuth 2.1 and there’s no reason to add it to a greenfield app in 2024+.

Middleware layering. Standard pattern — two middlewares, one for authentication, one for scope:

Route::middleware('auth.oauth')->group(function () {
    Route::get('/me', MeController::class);
    Route::middleware('oauth.scopes:orders.read')->group(function () {
        Route::get('/orders', OrderController::class);
    });
});

Verify in the source that the scope middleware rejects rather than silently passes when a scope is missing — a subtle inversion here is a classic Laravel OAuth bug. Write a feature test that hits a scoped route with a token missing the scope and asserts a 403.

Token issuance as a first-class action. Don’t hand-issue tokens in tests or seeders by inserting into the tokens table. Find the package’s token service (or the controller’s internal method) and use it, or you’ll create tokens that fail the middleware’s validation on expiry/revocation checks. If the package doesn’t expose one, that absence is itself a signal about its maturity — you’ll be writing that helper.

Testing patterns. For feature tests, generate a client + token per test (or a factory fixture in setUp), hit Authorization: Bearer ..., and assert. Don’t mock the middleware — mock the network layer of whatever client library is underneath, so you’re exercising the actual token verification path.

Revocation and refresh as explicit flows. Wire revocation into your logout / "disconnect account" path as its own endpoint call. Wire refresh into whatever your client SDK does, not into the resource server — the resource server should return 401 with a WWW-Authenticate: Bearer error="invalid_token" and let the client refresh. Get this separation right early; it’s hard to untangle later.

Gotchas and Tips

  • The package is unmaintained and unadopted. Read this as license to fork. Vendor it into your repo (or a repositories entry in composer.json pinned to a commit SHA — never a branch). Assign an owner. The moment you depend on it, you own it.
  • Migration names will collide. Any package that creates oauth_clients, oauth_tokens, oauth_scopes, etc. will fight with laravel/passport if it’s also installed, and with your own users foreign keys. Check the migrations before running php artisan migrate in an existing app — and never run them blind in production.
  • Token-at-rest encryption is not advertised. Verify that access tokens and especially refresh tokens are stored hashed or encrypted in the DB. A plaintext access_token column sitting in MySQL is fine for a demo and unacceptable in production. If the package stores them plaintext, add a Crypt mutator or wrap the model — but note that middleware lookups by token then require deterministic hashing, not Crypt (which is salted). This distinction is the most common mistake here.
  • Refresh token rotation and single-flight. If the package rotates refresh tokens on use, concurrent refresh attempts will invalidate each other, producing "random" logouts. Check the refresh handler for a DB transaction or lock. If neither exists, add Cache::lock("refresh:{$clientId}:{$userId}") at the application layer — do not trust the package to do this correctly.
  • Clock skew on token expiry. Token expiry comparisons without a safety margin (e.g. expires_at > now()->addSeconds(30)) produce intermittent 401s in load tests and under NTP drift. Confirm the margin, and add one if absent.
  • Debugging 401 vs 403. A 401 means the token is missing/invalid/expired; a 403 means valid token, insufficient scope. If both come back as 401 in this package, you will waste hours on scope bugs that look like auth bugs. Instrument the middleware and verify the distinction.
  • Config quirks. Config defaults often hard-code a TTL (e.g. 3600s) that later bites you when a client expects a longer-lived refresh token. Read the config file top to bottom before going live; every default is a decision you’re inheriting.
  • Extension points to look for (and to confirm actually work): a Token model you can subclass, an Authenticate middleware you can swap, and a service binding for the token repository. If the package hard-codes new Token, you cannot swap storage without forking.
  • The description / ecosystem mismatch is real. Some material describes this as an OAuth2 server (like Passport); some third-party write-ups treat it as an OAuth2 client connector. When you start reading source, resolve this in the first 15 minutes — the two have entirely different day-to-day ergonomics. Don't try to fit it into the wrong mental model.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle