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

Server Access Laravel Laravel Package

zpm-packages/server-access-laravel

Server Access for Laravel by ZPM Packages gives your Laravel app a clean, framework-native way to manage server access. Configure access rules, integrate checks with routes and resources, and keep authorization logic simple, consistent, and easy to maintain.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install and inspect before writing code

composer require zpm-packages/server-access-laravel
php artisan vendor:publish --provider="ZpmPackages\ServerAccess\ServerAccessServiceProvider"

Publish both the config and the migrations in one pass if the package offers tags (--tag=server-access-config, --tag=server-access-migrations); otherwise run the vendor:publish command twice and accept the provider prompt. Then inspect what you got:

  • config/server-access.php — the mode switch (direct vs database), connection/credential settings, and cache TTLs. Read this file end to end; it is the package's real API surface.
  • database/migrations/*_create_server_access_*.php — confirms the table names, foreign keys, and whether there's an expires_at / revoked_at column. This tells you whether access is time-boxed or boolean.
  • The service provider (bindings, singleton, mergeConfigFrom) — reveals the contract you can swap and whether anything is registered as a singleton you shouldn't mutate at runtime.
  • vendor/zpm-packages/server-access/src/ — the underlying domain package. The Laravel layer is thin; the real rules (how an access check is resolved, what "direct mode" means) live one level down.

Run php artisan migrate only after you've confirmed the table names don't collide with anything existing.

2. First use case: gate a route behind server access

The fastest meaningful integration is a single server record plus an access check on a route:

// App\Models\Server is yours, or use the package model if one is published
$server = ServerAccess::servers()->create([
    'name'     => 'web-01',
    'host'     => '10.0.1.10',
    'mode'     => 'database', // or 'direct'
]);

ServerAccess::grant($user, $server, ['role' => 'operator']);

Then protect routes:

Route::get('/servers/{server}/terminal', TerminalController::class)
    ->middleware(['auth', 'server-access']);

If the middleware alias isn't auto-registered, check bootstrap/app.php (Laravel 11+) or Kernel.php — the provider may only register the alias when a config flag is enabled.

Before you build on it: with 2 stars and zero dependents, treat the README as a starting hypothesis, not documentation. Verify every config key against the source using php artisan tinker → config('server-access') and confirm the migration columns match what the docs claim. Budget an hour to read the source before your first PR.

Implementation Patterns

Explicit mode selection per environment. The package advertises two modes: database-backed (access records in your DB, auditable, revocable) and direct (bypasses the DB, resolves access from configuration/direct source). Keep the mode in config, not in code:

// config/server-access.php
'mode' => env('SERVER_ACCESS_MODE', 'database'),

Use database in every environment where you need an audit trail. Reserve direct for local dev and CI, where you don't want to seed an access table. Never let direct leak into production via a missing env var — set the default to database and assert it in a health check.

Wrap checks in a Gate ability rather than calling the package directly. This keeps you decoupled and gives you one place to change when the package's API shifts:

// AppServiceProvider::boot()
Gate::define('operate-server', function (User $user, $server) {
    return ServerAccess::allows($user, $server, 'operator');
});

Then $this->authorize('operate-server', $server) in controllers and @can('operate-server', $server) in Blade. Every call site now depends on your abstraction, which matters for a package with this adoption level.

Bulk-resolve access instead of checking in a loop. Listing 50 servers and calling allows() per row is an N+1 against the access table. Look for a bulk resolver (ServerAccess::allowsFor($user, $servers) or a scoped query builder) and fall back to eager-loading the relation:

$servers = ServerAccess::servers()
    ->with(['access' => fn ($q) => $q->where('user_id', $user->id)])
    ->get();

Treat grant/revoke as domain events. Fire your own event alongside the package call so audit logging, Slack notifications, and cache busting have a hook:

DB::transaction(function () use ($user, $server) {
    ServerAccess::grant($user, $server, ['role' => 'operator', 'expires_at' => now()->addDays(7)]);
    AccessGranted::dispatch($user, $server);
});

If the package dispatches its own events, listen to those instead and delete your wrappers — but verify the event class actually exists before relying on it.

Sync from your identity source, don't hand-maintain. Access tables rot. Write a scheduled command that reconciles against your source of truth (team membership, LDAP group, IdP claims):

// app/Console/Commands/SyncServerAccess.php
foreach ($desiredGrants as $grant) {
    ServerAccess::grant(...$grant);
}
ServerAccess::query()->whereNotIn('id', $desiredIds)->delete();

Run it nightly and make it idempotent. This is the single highest-leverage thing you'll build on top of the package.

Drive automation through the same access layer. Scheduled jobs and deploy scripts should fetch credentials via the package rather than reading .env directly, so revocation takes effect immediately:

$conn = ServerAccess::connectionFor($user, $server); // however it's exposed

Testing. Bind a fake or swap the contract in TestCase::setUp so unit tests don't hit the DB. If no fake ships, wrap the package behind your own interface and fake that.

Gotchas and Tips

  • Cache invalidation is the #1 landmine. Access checks are almost certainly cached for performance. If a revoke doesn't take effect immediately, look for a cache key you need to forget — either the package exposes a flush()/forget() helper or you'll be calling Cache::tags(...)->flush(). Test revoke→request explicitly.
  • config:cache in production will freeze your env-driven mode. If your deploy runs php artisan config:cache, changing SERVER_ACCESS_MODE later does nothing until you re-cache. Add it to your deploy checklist.
  • Direct mode is unaudited by design. Anything that happens in direct mode leaves no row to inspect later. Don't use it for production break-glass access; you'll have no answer to "who had access on the 14th."
  • Secret storage and APP_KEY rotation. If server credentials are encrypted at rest (they should be), rotating APP_KEY without re-encrypting will silently break every connection. Confirm which key/cipher the package uses before any key rotation and rehearse it in staging.
  • Table name and migration collisions. With a generic namespace like server_access, servers, or access_grants, a collision with an existing table is plausible. Read the published migration before running it, and rename in the migration file (not after) if needed.
  • Expiry semantics are ambiguous. If there's an expires_at, check whether null means "never" or "expired", and whether the package filters expired rows in SQL or in PHP. Encode that in a test.
  • Version pinning. Last release is dated in the future relative to typical registries and the package has effectively no dependents. Pin to an exact version ("zpm-packages/server-access-laravel": "1.2.3") rather than ^. Run composer outdated deliberately, not automatically, and read the diff before upgrading.
  • Extension points to check, in order: (1) a container contract you can rebind in AppServiceProvider, (2) events dispatched on grant/revoke, (3) a driver/resolver registration hook in the config. If none exist, your only safe extension point is wrapping the facade — do that early, before call sites proliferate.
  • Debugging: php artisan tinker → app('server-access') to confirm the singleton resolves, then config('server-access') and ServerAccess::allows($user, $server) step by step. If checks return false unexpectedly, verify the model's primary key type (UUID vs int) and that the pivot/access row is actually using the right foreign key — mismatched key types are the most common silent failure in packages like this.
  • Have an exit plan. With no dependents and minimal community surface, assume you may need to fork. Keeping all calls behind a Gate and a single wrapper class means replacing the package later is a one-file change.
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo