Back to Home

Tyro Documentation

Complete guide to Authentication, Authorization, and Role & Privilege Management for Laravel 12

Introduction

Tyro is the ultimate Authentication, Authorization, and Role & Privilege Management solution for Laravel 12. Think of it as a Swiss Army knife that handles everything from user authentication and role-based access control to user suspension workflows—whether you're building an API, a traditional web application, or both.

With Sanctum integration, 40+ powerful CLI commands, Blade directives, ready-made middleware, and optional REST API endpoints, Tyro saves you weeks of development time while providing enterprise-grade security features.

✓ Works Everywhere: Tyro works seamlessly for APIs, web apps, and hybrid applications. Use the features you need, disable the ones you don't.

Why Choose Tyro?

Tyro isn't just a package; it's a complete auth and access control toolkit. Here is why developers choose Tyro:

Complete Auth System

Full authentication with Sanctum, role-based access control, privileges, and Laravel Gate integration. Works for APIs and web apps.

Secure by Default

Built on standard Laravel security. Assign roles and permissions to users with simple, readable code.

40+ CLI Commands

Manage users, roles, privileges, and tokens from the terminal. Perfect for automation, CI/CD, and incident response.

Grows With You

Start small and scale up without rewriting your core authentication logic. Tyro adapts to your project size.

Blade Directives

Use @hasrole, @hasprivilege, and more in your Blade templates. Clean, readable views without PHP logic clutter.

Optional REST API

Need API endpoints? They're included. Don't need them? Disable with one config flag. Zero lock-in.

Requirements

Before installing Tyro, ensure your environment meets these requirements:

  • PHP: 8.2 or higher
  • Laravel: 12.0 or higher
  • Laravel Sanctum: 4.0 or higher
  • Database: MySQL, PostgreSQL, SQLite, or SQL Server

Installation

Step 1: Install the Package

Install Tyro via Composer:

composer require hasinhayder/tyro

Step 2: Run the Installer

Run the all-in-one installer command:

php artisan tyro:install

This command automatically:

  • Calls Laravel's install:api to set up Sanctum
  • Runs database migrations
  • Seeds default roles and privileges
  • Prepares your User model with required traits
💡 Tip: The installer is idempotent and safe to run multiple times. Use --force flag in production environments.

Step 3: Verify Installation

Check that everything is set up correctly:

php artisan tyro:version

Quick Start

After installation, you have a complete authentication and authorization system. Here's what you can do immediately:

1. Login with Default Admin

curl -X POST http://localhost/api/login \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"email":"admin@tyro.project","password":"tyro"}'

2. Use the Token

Save the token from the response and use it in subsequent requests:

curl http://localhost/api/me \ -H "Authorization: Bearer YOUR_TOKEN_HERE"

3. Check Permissions in Code

Use Tyro's intuitive API anywhere in your application:

// Check roles if ($user->hasRole('admin')) { ... } // Check privileges if ($user->can('reports.run')) { ... } // Get all role slugs $roles = $user->tyroRoleSlugs(); // ['admin', 'editor']

4. Use Blade Directives

Conditionally render content in your views:

@hasrole('admin') <p>Welcome, Admin!</p> @endhasrole @hasprivilege('edit-posts') <button>Edit Post</button> @endhasprivilege

5. Protect Routes

Use middleware to protect your routes:

Route::middleware(['auth:sanctum', 'role:admin']) ->get('/admin/dashboard', DashboardController::class);
✓ You're Ready! With just 2 commands, you now have complete authentication, authorization, roles, privileges, 7 Blade directives, middleware, and 40+ CLI commands.

Roles & Privileges

Tyro uses a flexible role-privilege system where roles (like "admin", "editor") can have multiple privileges (like "reports.run", "billing.view"). Users are assigned roles and inherit all privileges from those roles.

Default Roles

Tyro seeds these roles by default:

Role Slug Description
Super Admin super-admin Full system access with all privileges
Administrator admin Administrative access to manage users and roles
Editor editor Content management privileges
User user Default role for new registrations
Customer customer Customer-specific access

Working with Privileges

Create and attach privileges to roles:

# Create a new privilege php artisan tyro:add-privilege reports.run --name="Run Reports" # Attach it to a role php artisan tyro:attach-privilege reports.run editor

Authentication

Tyro uses Laravel Sanctum for API authentication. Tokens automatically include all role and privilege slugs as abilities.

Generating Tokens via CLI

# Generate token with password prompt php artisan tyro:login --user=admin@tyro.project # Quick token without password (development only) php artisan tyro:quick-token --user=1

Token Inspection

Inspect what a token contains:

php artisan tyro:me

Then paste your token when prompted to see the user and abilities.

Middleware

Tyro provides powerful middleware for protecting your routes:

Middleware Usage Description
ability ability:admin,reports.run Require ALL listed abilities
abilities abilities:admin,editor Allow ANY of the listed abilities
role role:admin Require ALL listed roles
roles roles:admin,editor Allow ANY of the listed roles
privilege privilege:reports.run Require ALL listed privileges
privileges privileges:billing.view Allow ANY of the listed privileges
tyro.log tyro.log Log request/response pairs for auditing

Example Usage

use Illuminate\Support\Facades\Route; // Require admin role Route::middleware(['auth:sanctum', 'role:admin']) ->get('/admin/dashboard', DashboardController::class); // Allow either admin or editor Route::middleware(['auth:sanctum', 'roles:admin,editor']) ->post('/articles', ArticleController::class); // Require specific privilege Route::middleware(['auth:sanctum', 'privilege:reports.run']) ->get('/reports', ReportController::class);

Blade Directives

Tyro provides custom Blade directives for checking user roles and privileges directly in your views. All directives automatically return false if no user is authenticated.

@usercan

Checks if the current user has a specific role or privilege (uses the can() method):

@usercan('admin') <div class="admin-panel"> <h2>Admin Dashboard</h2> <p>Welcome to the admin area!</p> </div> @endusercan @usercan('edit-posts') <button class="btn btn-primary">Edit Post</button> @endusercan

@hasrole

Checks if the current user has a specific role:

@hasrole('admin') <p>Welcome, Admin!</p> @endhasrole @hasrole('editor') <a href="/dashboard/editor" class="nav-link">Editor Dashboard</a> @endhasrole

@hasanyrole

Checks if the current user has any of the provided roles:

@hasanyrole('admin', 'editor', 'moderator') <div class="management-tools"> <h3>Management Tools</h3> <p>You have access to management features</p> </div> @endhasanyrole

@hasroles

Checks if the current user has all of the provided roles:

@hasroles('admin', 'super-admin') <div class="super-admin-panel"> <p>You have both admin and super-admin privileges</p> <button class="btn-danger">Critical Actions</button> </div> @endhasroles

@hasprivilege

Checks if the current user has a specific privilege:

@hasprivilege('delete-users') <button class="btn btn-danger" onclick="deleteUser()"> Delete User </button> @endhasprivilege @hasprivilege('view-reports') <a href="/reports" class="nav-link"> <i class="icon-reports"></i> View Reports </a> @endhasprivilege

@hasanyprivilege

Checks if the current user has any of the provided privileges:

@hasanyprivilege('edit-posts', 'delete-posts', 'publish-posts') <div class="post-actions"> <h4>Post Management</h4> @hasprivilege('edit-posts') <button>Edit</button> @endhasprivilege @hasprivilege('delete-posts') <button>Delete</button> @endhasprivilege </div> @endhasanyprivilege

@hasprivileges

Checks if the current user has all of the provided privileges:

@hasprivileges('create-invoices', 'approve-invoices') <button class="btn btn-success" onclick="createAndApproveInvoice()"> Create and Approve Invoice </button> @endhasprivileges @hasprivileges('view-reports', 'export-reports') <div class="reports-section"> <a href="/reports">View Reports</a> <button onclick="exportReport()">Export</button> </div> @endhasprivileges

Combining Directives

You can nest and combine directives for complex authorization logic:

@hasrole('admin') <div class="admin-section"> <h2>Admin Controls</h2> @hasprivilege('manage-users') <a href="/admin/users">Manage Users</a> @endhasprivilege @hasanyprivilege('view-reports', 'export-data') <a href="/admin/reports">Reports</a> @endhasanyprivilege </div> @endhasrole @hasanyrole('editor', 'author') <div class="content-tools"> @hasprivilege('publish-posts') <button>Publish</button> @else <button disabled>Publish (requires approval)</button> @endhasprivilege </div> @endhasanyrole
✓ Auto-Registered: All directives are automatically registered when the Tyro package is loaded. They provide a clean, readable way to conditionally display content based on user permissions.

User Suspension

Tyro includes first-class user suspension support to freeze accounts without deleting them.

Suspending Users

# Via CLI php artisan tyro:suspend-user --user=user@example.com --reason="Policy violation" # Via Code $user->suspend('Policy violation');

Unsuspending Users

# Via CLI php artisan tyro:unsuspend-user --user=user@example.com # Via Code $user->unsuspend();

Checking Suspension Status

if ($user->isSuspended()) { $reason = $user->getSuspensionReason(); return response()->json(['error' => $reason], 423); }
⚠️ Important: Suspending a user automatically revokes all their Sanctum tokens and prevents login.

HasTyroRoles Trait Reference

The HasTyroRoles trait gives your User model a complete API for roles, privileges, and suspensions. These methods are the same ones used by Tyro's routes and CLI commands.

Role Methods

Method Description
roles(): BelongsToMany Returns the eager-loadable relationship for roles
assignRole(Role $role): void Attaches a role without detaching existing ones
removeRole(Role $role): void Detaches the given role from the user
hasRole(string $role): bool Checks if user has the specified role slug (supports wildcard *)
hasRoles(array $roles): bool Returns true only if user holds every role in the array
tyroRoleSlugs(): array Returns array of all role slugs for the user (cached)

Privilege Methods

Method Description
privileges(): Collection Returns all unique privileges inherited through user's roles
hasPrivilege(string $privilege): bool Checks if user has a specific privilege
hasPrivileges(array $privileges): bool Returns true only if user has all specified privileges
tyroPrivilegeSlugs(): array Returns array of all privilege slugs for the user (cached)
can($ability, $args = []): bool Checks privilege, then role, then falls back to Laravel Gate

Suspension Methods

Method Description
suspend(?string $reason = null): void Suspends user, stores optional reason, revokes all tokens
unsuspend(): void Clears suspension without touching roles or privileges
isSuspended(): bool Returns true if user is currently suspended
getSuspensionReason(): ?string Returns the stored suspension reason (or null)
💡 Performance: Tyro caches role and privilege slugs per user so authorization checks never hit the database on every request. The cache respects your config/tyro.php settings.

Setup & Installation Commands

tyro:install
Run Laravel's install:api, migrate, and optionally seed or prepare user model
php artisan tyro:install
tyro:prepare-user-model
Automatically add HasApiTokens and HasTyroRoles to your User model
php artisan tyro:prepare-user-model
tyro:seed
Run the full TyroSeeder (roles + bootstrap admin)
php artisan tyro:seed --force
tyro:publish-config
Publish config/tyro.php to customize settings
php artisan tyro:publish-config --force
tyro:publish-migrations
Copy Tyro's migrations into your database/migrations directory
php artisan tyro:publish-migrations --force

User Management Commands

tyro:create-user
Create a new user with interactive prompts
php artisan tyro:create-user
tyro:users
List all users with their roles and suspension status
php artisan tyro:users
tyro:suspend-user
Suspend a user account with optional reason
php artisan tyro:suspend-user --user=5 --reason="Manual review"
tyro:unsuspend-user
Lift suspension from a user account
php artisan tyro:unsuspend-user --user=user@example.com
tyro:user-privileges
Display all privileges a user inherits through their roles
php artisan tyro:user-privileges 1

Role & Privilege Commands

tyro:roles
Display all roles with user counts
php artisan tyro:roles
tyro:roles-with-privileges
Display roles with their attached privileges
php artisan tyro:roles-with-privileges
tyro:create-role
Create a new role
php artisan tyro:create-role --name="Manager" --slug="manager"
tyro:assign-role
Assign a role to a user
php artisan tyro:assign-role --user=5 --role=editor
tyro:add-privilege
Create a new privilege
php artisan tyro:add-privilege reports.run --name="Run Reports"
tyro:attach-privilege
Attach a privilege to a role
php artisan tyro:attach-privilege reports.run editor
tyro:detach-privilege
Remove a privilege from a role
php artisan tyro:detach-privilege reports.run editor

Token Management Commands

tyro:login
Generate a Sanctum token with password verification
php artisan tyro:login --user=admin@tyro.project
tyro:quick-token
Generate a token without password (development only)
php artisan tyro:quick-token --user=1
tyro:me
Inspect a token to see user and abilities
php artisan tyro:me
tyro:logout-all-users
Revoke all tokens for all users (emergency rotation)
php artisan tyro:logout-all-users --force

Checking Permissions

Check User Roles

use Illuminate\Http\Request; class ArticleController { public function store(Request $request) { // Check single role if (!$request->user()->hasRole('admin')) { abort(403, 'Admin access required'); } // Check multiple roles (requires ALL) if (!$request->user()->hasRoles(['admin', 'editor'])) { abort(403, 'Insufficient permissions'); } // Create article... } }

Check User Privileges

class ReportController { public function index(Request $request) { // Check single privilege using can() if (!$request->user()->can('reports.run')) { abort(403, 'Missing reports privilege'); } // Check multiple privileges (requires ALL) if (!$request->user()->hasPrivileges(['reports.run', 'billing.view'])) { abort(403, 'Missing required privileges'); } // Generate report... } }

Get User's Roles and Privileges

// Get role slugs $roleSlugs = $request->user()->tyroRoleSlugs(); // Get privilege slugs $privilegeSlugs = $request->user()->tyroPrivilegeSlugs(); // Get full role models with relationships $roles = $request->user()->roles()->with('privileges')->get();

Managing Roles Programmatically

Assign Roles to Users

use HasinHayder\Tyro\Models\Role; use App\Models\User; $user = User::find(1); $editorRole = Role::where('slug', 'editor')->first(); // Assign a single role $user->assignRole($editorRole); // Or use the relationship directly $user->roles()->attach($editorRole->id);

Remove Roles from Users

// Remove a single role $user->removeRole($editorRole); // Or use the relationship $user->roles()->detach($editorRole->id); // Remove all roles $user->roles()->detach();

Manage Privileges on Roles

use HasinHayder\Tyro\Models\Privilege; $role = Role::where('slug', 'editor')->first(); $privilege = Privilege::where('slug', 'reports.run')->first(); // Attach privilege to role $role->privileges()->attach($privilege->id); // Detach privilege from role $role->privileges()->detach($privilege->id); // Sync privileges (replaces all existing) $role->privileges()->sync([ $privilege1->id, $privilege2->id, ]);

Check Role Privileges

$role = Role::where('slug', 'editor')->first(); // Check if role has a privilege if ($role->hasPrivilege('reports.run')) { // Role has the privilege } // Check if role has all specified privileges if ($role->hasPrivileges(['reports.run', 'billing.view'])) { // Role has both privileges }

Protecting API Routes

Basic Route Protection

use Illuminate\Support\Facades\Route; // Require authentication Route::middleware(['auth:sanctum']) ->get('/profile', ProfileController::class); // Require specific role Route::middleware(['auth:sanctum', 'role:admin']) ->get('/admin/dashboard', AdminDashboardController::class); // Allow any of multiple roles Route::middleware(['auth:sanctum', 'roles:admin,editor']) ->post('/articles', ArticleController::class);

Privilege-Based Protection

// Require specific privilege Route::middleware(['auth:sanctum', 'privilege:reports.run']) ->get('/reports', ReportController::class); // Allow any of multiple privileges Route::middleware(['auth:sanctum', 'privileges:billing.view,reports.run']) ->get('/analytics', AnalyticsController::class);

Mixed Abilities (Roles + Privileges)

// Require ALL abilities (roles and/or privileges) Route::middleware(['auth:sanctum', 'ability:admin,reports.run']) ->post('/reports/export', ReportExportController::class); // Allow ANY ability Route::middleware(['auth:sanctum', 'abilities:admin,super-admin,reports.run']) ->get('/reports/advanced', AdvancedReportController::class);

With Audit Logging

// Add tyro.log middleware for request/response logging Route::middleware(['auth:sanctum', 'ability:billing.view', 'tyro.log']) ->get('/billing/statements', BillingStatementController::class);

API Endpoints Reference

Complete list of available API endpoints in Tyro.

Public Endpoints

Method Endpoint Description
POST /api/login Authenticate user and retrieve token
POST /api/users Register a new user
GET /api/tyro Get Tyro package information
GET /api/tyro/version Get installed Tyro version

Authenticated User Endpoints

Requires auth:sanctum middleware.

Method Endpoint Description
GET /api/me Get current authenticated user profile
PUT/PATCH /api/users/{user} Update own profile (requires user ability)

Admin Endpoints

Requires auth:sanctum and admin abilities.

User Management

Method Endpoint Description
GET /api/users List all users
GET /api/users/{user} Get specific user details
DELETE /api/users/{user} Delete a user
POST /api/users/{user}/suspend Suspend a user account
DELETE /api/users/{user}/suspend Unsuspend a user account

Role & Privilege Management

Method Endpoint Description
GET /api/roles List all roles
POST /api/roles Create a new role
GET /api/roles/{role} Get role details
PUT/PATCH /api/roles/{role} Update a role
DELETE /api/roles/{role} Delete a role
GET /api/privileges List all privileges
POST /api/privileges Create a new privilege
GET /api/privileges/{privilege} Get privilege details
PUT/PATCH /api/privileges/{privilege} Update a privilege
DELETE /api/privileges/{privilege} Delete a privilege

Assignments

Method Endpoint Description
GET /api/users/{user}/roles List roles assigned to user
POST /api/users/{user}/roles Assign role to user
DELETE /api/users/{user}/roles/{role} Remove role from user
GET /api/roles/{role}/privileges List privileges in role
POST /api/roles/{role}/privileges Attach privilege to role
DELETE /api/roles/{role}/privileges/{privilege} Detach privilege from role

Configuration

Publish the configuration file to customize Tyro:

php artisan tyro:publish-config --force

Key Configuration Options

Option Default Description
guard sanctum Authentication guard for protected routes
route_prefix api URL prefix for all Tyro routes
default_user_role_slug user Role assigned to new registrations
cache.enabled true Enable role/privilege caching
disable_api false Disable built-in API routes
disable_commands false Disable artisan commands

Environment Variables

# Disable commands in production TYRO_DISABLE_COMMANDS=true # Disable API routes TYRO_DISABLE_API=true

Frequently Asked Questions

How do I change the default admin credentials?

After installation, immediately change the default admin password using:

php artisan tyro:update-user --user=admin@tyro.project --password=new_secure_password

Can I use Tyro with an existing Laravel project?

Yes! Tyro is designed to integrate seamlessly with existing projects. Just run tyro:install and it will set up alongside your existing code without conflicts.

How do I disable Tyro's built-in routes?

Set TYRO_DISABLE_API=true in your .env file to disable all built-in routes and implement your own.

What happens when I suspend a user?

Suspending a user sets a suspended_at timestamp, stores an optional reason, and immediately revokes all their Sanctum tokens. They cannot log in until unsuspended.

How do I add custom roles and privileges?

Use the artisan commands or create them programmatically:

# Via CLI php artisan tyro:create-role --name="Manager" --slug="manager" php artisan tyro:add-privilege custom.action --name="Custom Action" # Via Code Role::create(['name' => 'Manager', 'slug' => 'manager']); Privilege::create(['name' => 'Custom Action', 'slug' => 'custom.action']);

Is Tyro production-ready?

Yes! Tyro is battle-tested and includes comprehensive security features, caching, and performance optimizations. It's used in production applications.

How do I get help or report bugs?

Visit the GitHub repository to open issues, read the full README, or contribute to the project.

← Back to Home