π Laravel 11 API Token Generation: Build a Secure Artisan Command with Sanctum
π The Ultimate Artisan Command for Secure API Authentication
In modern Laravel applications, API authentication is often handled using Laravel Sanctum. While Sanctum provides excellent functionality out of the box, creating a robust token generation command can streamline your development workflow and enhance security. Let's build a powerful Artisan command that handles token generation with expiration dates and user management. i will not talk about the Laravel Sanctum installation and setup, you can find that in the Laravel Sanctum documentation.
π‘ Why Build a Custom Token Command?
| Benefit | Description |
|---|---|
| β±οΈ Time-Saving | Generate tokens faster than manual methods |
| π Enhanced Security | Built-in expiration handling and token rotation |
| π€ Automation Ready | Integrates with deployment scripts and CI/CD pipelines |
| π Consistent Process | Standardized token generation across your team |
| π οΈ Developer Experience | Beautiful CLI interface with interactive prompts |
π οΈ Implementation Deep Dive
1. The Token Generation Action (app/Actions/GenerateTokenAction.php)
This action handles the core logic of generating a token for a user. It checks if the user exists, creates a new one if not, and generates a token with an optional expiration date.
<?php declare(strict_types=1); namespace App\Actions; use Carbon\Carbon;use App\Models\User;use Illuminate\Support\Str;use Illuminate\Support\Facades\Hash; final class GenerateTokenAction{ public function execute(string $username, ?string $expires = null): array { $user = User::query() ->firstOrCreate( ['email' => $username], [ 'name' => $username, 'password' => Hash::make(Str::random(16)), ] ); $user->tokens()->delete(); $expiresAt = $expires !== null && $expires !== '' && $expires !== '0' ? Carbon::parse($expires) : null; $token = $user->createToken( name: $username, expiresAt: $expiresAt, ); return [ 'user' => $user->name, 'token' => $token->plainTextToken, 'expires_at' => $expiresAt, 'created_at' => $user->created_at, ]; }}
Key Features:
- π Automatic token rotation (deletes old tokens)
- π Secure password generation for new users
- β³ Flexible expiration handling
- π¦ Clean, standardized return format
2. The Artisan Command (app/Console/Commands/GenerateToken.php)
Create a new Artisan command using the following command:
php artisan make:command GenerateToken
After that, replace the contents of the generated file with the following code:
<?php declare(strict_types=1); namespace App\Console\Commands; use App\Actions\GenerateTokenAction;use Illuminate\Console\Command;use Illuminate\Contracts\Console\PromptsForMissingInput;use Symfony\Component\Console\Input\InputInterface;use Symfony\Component\Console\Output\OutputInterface;use function Laravel\Prompts\{clear, confirm, info, progress, text}; final class GenerateToken extends Command implements PromptsForMissingInput{ protected $signature = 'generate:token {username : User email or username} {expires? : Expiration date (e.g. "1 day", "2025-12-31")}'; protected $description = 'Generate or update user token with expiration'; public function handle(GenerateTokenAction $action): void { $expires = $this->argument('expires') === 'yes' ? text('Enter expiration (e.g., "1 day", "2025-12-31")') : $this->argument('expires'); $results = progress( label: 'Generating token', steps: 1, callback: function () use ($action, $expires): array { sleep(1); // Simulate a delay for the progress bar note: this is just for demonstration return $action->execute( username: $this->argument('username'), expires: $expires, ); }, ); // Extract the first (and only) result from the progress array $result = $results[0]; $this->line(''); info('β
API Token Generated Successfully'); $this->table( ['π User', 'π Token', 'β³ Expires At'], [ [ $result['user'], $result['token'], $result['expires_at']->toDateTimeString(), ], ] ); } protected function promptForMissingArgumentsUsing(): array { return [ 'username' => 'Enter the username or email address', ]; } protected function afterPromptingForMissingArguments(InputInterface $input, OutputInterface $output): void { if (confirm('Do you want to set an expiration date for the token?')) { $input->setArgument( 'expires', text('Enter expiration (e.g., "1 day", "2025-12-31")') ); } }}
UX Enhancements:
- π¨ Color-coded output
- π Progress indicators
- β Interactive prompts
- π Clear, organized information display
ποΈ Usage Examples
π§ Basic Interactive Mode
php artisan generate:token
Prompts for:
- Username/Email address
- Whether to set expiration
- Expiration timeframe if selected
β‘ Direct Command Usage
# Token without expiration # Token with 30-day expiration
π€ CI/CD Integration
# Create deployment token (expires in 1 hour)
Output
β
API Token Generated Successfully +---------+-----------------------------------------------------+---------------------+| π User | π Token | β³ Expires At |+---------+-----------------------------------------------------+---------------------+| bb | 50|q2uPCYho0wHnZ2AvPtBia8IB8hp9hRWpfqUD8crA20370e93 | 2025-05-15 07:49:51 |+---------+-----------------------------------------------------+---------------------+
π Advanced Extensions
you can enhance more features such as given in flow chart.
π― Conclusion
This implementation provides:
- Enterprise-grade security π in a developer-friendly package
- Beautiful CLI UX π¨ that teams will love using
- Production-ready features ποΈ out of the box
- Extensible architecture βοΈ for future needs