berny/one-time-access-bundle
Installation:
composer require xphere/one-time-access-bundle
Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 2/3):
// config/bundles.php
return [
// ...
xPheRe\OneTimeAccessBundle\xPheReOneTimeAccessBundle::class => ['all' => true],
];
Configure Firewall:
Add the one_time_access key to your firewall in config/packages/security.yaml (Symfony 4+) or app/config/security.yml (Symfony 2/3):
security:
firewalls:
ota:
one_time_access:
route: app_ota_auth # Must match your route name
# Optional: Customize token TTL (default: 3600 seconds)
ttl: 3600
Create a Route:
Define a route for the one-time access URL (e.g., routes/ota.yaml):
app_ota_auth:
path: /auth/{token}
controller: xPheRe\OneTimeAccessBundle\Controller\OneTimeAccessController::authenticateAction
requirements:
token: '[a-zA-Z0-9_-]{32}'
Generate a Token:
Use the OneTimeAccessGenerator service to create a token for a user:
use xPheRe\OneTimeAccessBundle\Generator\OneTimeAccessGenerator;
$generator = $this->container->get('xphere_one_time_access.generator');
$token = $generator->generateToken($user);
Share this token via email/SMS (e.g., in a "Forgot Password" flow).
Trigger Token Generation:
In your User controller, generate a token when a user requests access:
public function requestAccess(User $user, OneTimeAccessGenerator $generator)
{
$token = $generator->generateToken($user);
// Send $token via email/SMS to the user.
return new Response('Check your email for a one-time login link.');
}
User Clicks Link:
The user visits /auth/{token}. The firewall validates the token, logs them in, and redirects to the dashboard.
$token = $generator->generateToken($user, ['ip' => $request->getClientIp()]);
Optional: Bind tokens to metadata (e.g., IP, user agent) for security.# config/packages/security.yaml
firewalls:
ota:
one_time_access:
route: app_ota_auth
events:
on_auth_success: app.ota.on_auth_success
on_auth_failure: app.ota.on_auth_failure
Use separate firewalls for different use cases (e.g., admin vs. user OTA):
firewalls:
user_ota:
one_time_access:
route: app_user_ota_auth
ttl: 1800 # 30 minutes
admin_ota:
one_time_access:
route: app_admin_ota_auth
ttl: 3600
# Custom provider
provider: admin_user_provider
OneTimeAccessManager:
$manager = $this->container->get('xphere_one_time_access.manager');
$manager->revokeToken($token);
Service Container:
Bind the Symfony services to Laravel’s container in AppServiceProvider:
public function register()
{
$this->app->bind('xphere_one_time_access.generator', function ($app) {
return new \xPheRe\OneTimeAccessBundle\Generator\OneTimeAccessGenerator(
$app['xphere_one_time_access.manager'],
$app['xphere_one_time_access.token_storage']
);
});
}
Middleware: Replace Symfony’s firewall with Laravel middleware. Create a custom middleware to handle OTA:
namespace App\Http\Middleware;
use Closure;
use xPheRe\OneTimeAccessBundle\Generator\OneTimeAccessGenerator;
class OneTimeAccessMiddleware
{
protected $generator;
public function __construct(OneTimeAccessGenerator $generator)
{
$this->generator = $generator;
}
public function handle($request, Closure $next)
{
$token = $request->route('token');
// Validate token and set user...
return $next($request);
}
}
Register it in app/Http/Kernel.php:
protected $routeMiddleware = [
'ota' => \App\Http\Middleware\OneTimeAccessMiddleware::class,
];
Routing: Use Laravel’s routing syntax:
Route::get('/auth/{token}', [OneTimeAccessController::class, 'authenticateAction'])
->middleware('ota')
->name('app.ota_auth');
Extend the default generator to add metadata (e.g., user agent, IP):
namespace App\Services;
use xPheRe\OneTimeAccessBundle\Generator\OneTimeAccessGenerator as BaseGenerator;
class CustomOneTimeAccessGenerator extends BaseGenerator
{
public function generateToken($user, array $metadata = [])
{
$metadata['user_agent'] = request()->userAgent();
$metadata['ip'] = request()->ip();
return parent::generateToken($user, $metadata);
}
}
Bind it in AppServiceProvider:
$this->app->bind('xphere_one_time_access.generator', function ($app) {
return new CustomOneTimeAccessGenerator(
$app['xphere_one_time_access.manager'],
$app['xphere_one_time_access.token_storage']
);
});
Token Storage:
security.token_storage by default. In Laravel, ensure this is properly mocked or replaced.Auth facade to store the user after validation:
Auth::login($user);
Route Requirements:
token regex ([a-zA-Z0-9_-]{32}). Customize this in your route:
app_ota_auth:
path: /auth/{token}
requirements:
token: '[a-zA-Z0-9_-]{43}' # Adjust length as needed
Firewall Configuration:
one_time_access key must include a route. Omitting this will cause a ConfigurationException.No route defined for one-time access firewall.route: your_route_name.Token Revocation:
public function authenticateAction($token)
{
// Validate token...
$manager->revokeToken($token); // Revoke after use
Auth::login($user);
return redirect('/dashboard');
}
Symfony-Specific Assumptions:
UserInterface. For Laravel, ensure your User model implements Symfony\Component\Security\Core\User\UserInterface:
use Symfony\Component\Security\Core\User\UserInterface;
class User implements UserInterface
{
// ...
}
Token Validation Failures:
$manager = $this->container->get('xphere_one_time_access.manager');
$tokenData = $manager->findToken($token);
Firewall Not Triggering:
route key in the firewall config.dump() in a custom event listener for on_auth_attempt.User Not Logged In:
TokenStorage is updated after validation. In Laravel, use Auth::login($user) explicitly.How can I help you explore Laravel packages today?