Installation
Add the bundle to composer.json:
{
"require": {
"bitgrave/persona-bundle": "dev-master"
}
}
Run composer update or composer install.
Enable the Bundle
Register BGPersonaBundle in app/AppKernel.php:
new BGPersonaBundle(),
Configure Security
Update app/config/security.yml to include the Persona provider:
providers:
persona:
id: bg_persona.security.persona_user_provider
firewalls:
main:
pattern: ^/
form_login:
provider: persona
login_path: /login
check_path: /login_check
logout: true
Add Login Button
Include the Twig helper in your login template (app/Resources/views/Security/login.html.twig):
{{ persona_login_button() }}
Test the Flow
/login.test@example.com)./).BGPersonaBundle is the only provider in security.yml.test@example.com).var_dump($this->getUser()) in a controller to confirm authentication.Extend User Provider Override the default provider to sync Persona logins with FOSUserBundle:
# app/config/security.yml
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
persona:
id: bg_persona.security.persona_user_provider
# Custom provider class (see below)
Custom User Provider Create a service to merge Persona and FOSUser data:
// src/Acme/AppBundle/Service/PersonaFosUserProvider.php
class PersonaFosUserProvider implements UserProviderInterface {
private $personaProvider;
private $fosProvider;
public function __construct(PersonaUserProvider $personaProvider, UserProviderInterface $fosProvider) {
$this->personaProvider = $personaProvider;
$this->fosProvider = $fosProvider;
}
public function loadUserByUsername($username) {
// Try FOSUser first, fall back to Persona
try {
return $this->fosProvider->loadUserByUsername($username);
} catch (UsernameNotFoundException $e) {
return $this->personaProvider->loadUserByUsername($username);
}
}
}
Configure the Service
# app/config/services.yml
services:
acme.persona_fos_user_provider:
class: Acme\AppBundle\Service\PersonaFosUserProvider
arguments:
- '@bg_persona.security.persona_user_provider'
- '@fos_user.user_provider.username_email'
Update Security
# app/config/security.yml
providers:
merged:
id: acme.persona_fos_user_provider
Override Twig Helper Extend the default button template:
{# app/Resources/views/BGPersona/login_button.html.twig #}
<a href="{{ path('bg_persona_login') }}" class="btn-persona">
<img src="{{ asset('bundles/bgpersona/images/persona-logo.png') }}" alt="Login with Persona">
</a>
Update Routes
Ensure bg_persona_login route is configured in routing.yml:
bg_persona_login:
path: /login/persona
defaults: { _controller: BGPersonaBundle:Security:login }
Custom Error Handling
Override the PersonaAuthenticationListener to handle failures:
// src/Acme/AppBundle/EventListener/PersonaAuthListener.php
class PersonaAuthListener {
public function onAuthenticationFailure(Request $request, AuthenticationException $exception) {
if ($exception instanceof PersonaException) {
// Log or redirect with custom message
$request->getSession()->getFlashBag()->add('error', 'Persona login failed: ' . $exception->getMessage());
}
}
}
Register the Listener
# app/config/services.yml
services:
acme.persona_auth_listener:
class: Acme\AppBundle\EventListener\PersonaAuthListener
tags:
- { name: kernel.event_listener, event: security.authentication.failure, method: onAuthenticationFailure }
Deprecated API
Symfony 2.1 Dependency
No Persistent Sessions
Email-Only Authentication
Enable Verbose Logging
Add to app/config/config.yml:
monolog:
handlers:
main:
level: debug
channels: ["!event"]
Check Persona API Calls
https://verifier.login.persona.org. Use browser dev tools or strace:
strace -e trace=network -f php app/console
Validate Email Format
test@example.com). Invalid emails (e.g., test) will fail silently.// app/Resources/public/js/login.js
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
alert('Please enter a valid email (e.g., test@example.com)');
}
Custom User Data Mapping
PersonaUser to include additional fields (e.g., name, avatar):
// src/Acme/AppBundle/Model/PersonaUser.php
class PersonaUser extends User implements UserInterface {
private $avatarUrl;
public function setAvatarUrl($url) {
$this->avatarUrl = $url;
}
}
Post-Authentication Logic
security.interactive_login event:
services:
acme.persona_post_auth_handler:
class: Acme\AppBundle\EventListener\PersonaPostAuthHandler
tags:
- { name: kernel.event_listener, event: security.interactive_login, method: onPostAuth }
Multi-Factor Authentication (MFA)
friendsofsymfony/user-bundle):
# app/config/security.yml
firewalls:
main:
form_login:
provider: merged
remember_me:
key: "persona_remember_me"
lifetime: 31536000 # 1 year
Domain Whitelisting
curl -X POST https://verifier.login.persona.org/verify -d "assertion=test@example.com"
CSRF Protection
{{ form_start(form, { 'attr
How can I help you explore Laravel packages today?