Installation:
composer require dunglas/angular-csrf-bundle
Add to config/bundles.php (Symfony 4+ auto-discovers, but ensure it's enabled):
Dunglas\AngularCsrfBundle\DunglasAngularCsrfBundle::class => ['all' => true],
Enable CSRF Token in Templates:
Add this to your base template (e.g., base.html.twig):
{{ csrf_token('angular_csrf') }}
This injects a hidden <meta> tag with the CSRF token.
AngularJS Service Integration:
In your AngularJS app, inject the $http service and configure it to include the CSRF token:
angular.module('myApp').config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.headers.common['X-CSRF-Token'] = angular.element('meta[name="csrf-token"]').attr('content');
}]);
Symfony Configuration:
Ensure csrf_protection is enabled in config/packages/security.yaml:
security:
enable_authenticator_manager: true
csrf_protection:
enabled: true
For a simple AngularJS app making API calls to Symfony:
/api/users) will automatically validate the X-CSRF-Token header.$http requests will include the token via the configured header.Server-Side:
<meta> tag (default) or a custom header (X-CSRF-Token).config/packages/dunglas_angular_csrf.yaml:
dunglas_angular_csrf:
token_name: 'X-CSRF-Token' # Optional: Override default
Client-Side:
<meta> tag or uses a hardcoded value (not recommended).angular.module('myApp').factory('CsrfService', ['$http', function($http) {
return {
getToken: function() {
return angular.element('meta[name="csrf-token"]').attr('content');
}
};
}]);
Symfony Forms: If using Symfony forms with AngularJS, ensure the form includes the CSRF token:
{{ form_start(form, { attr: { 'data-csrf-token': csrf_token('angular_csrf') } }) }}
API Platform: For API Platform, the bundle works out-of-the-box. No additional config is needed if using AngularJS clients.
Non-AngularJS Clients: The bundle is framework-agnostic. For React/Vue, manually include the token in headers:
// React example
fetch('/api/endpoint', {
headers: {
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
}
});
Token Rotation:
Regenerate the token on login/logout by clearing the <meta> tag and re-rendering the template:
{% if app.user %}
{{ csrf_token('angular_csrf') }}
{% endif %}
Token Mismatch:
<meta> tag or using a service to fetch a new one from /_csrf_token.CORS Issues:
X-CSRF-Token header.# config/packages/nelmio_cors.yaml
nelmio_cors:
defaults:
allow_headers: ['X-CSRF-Token', 'Origin', 'Content-Type']
Archived Status:
DneustadtCsrfCookieBundle.Double Submissions:
$http interceptors to handle errors gracefully.Check Headers:
Use browser dev tools (Network tab) to verify the X-CSRF-Token header is sent with requests.
Symfony Logs: Enable debug mode to see CSRF validation errors:
# config/packages/dev/monolog.yaml
monolog:
handlers:
main:
level: debug
Token Expiration: The token expires after each request. For long-lived sessions (e.g., WebSockets), regenerate it periodically.
Custom Token Storage:
Override the token storage mechanism by extending the bundle's TokenStorage service:
// src/Service/CustomTokenStorage.php
class CustomTokenStorage implements TokenStorageInterface {
public function getToken(): string {
return 'custom-token-value';
}
}
Register it as a service in config/services.yaml:
services:
App\Service\CustomTokenStorage:
tags: ['dunglas_angular_csrf.token_storage']
Token Generation:
Extend the TokenGenerator to use a custom strategy (e.g., UUID-based tokens):
class CustomTokenGenerator implements TokenGeneratorInterface {
public function generateToken(): string {
return bin2hex(random_bytes(16));
}
}
Bind it in config/services.yaml:
services:
App\Service\CustomTokenGenerator:
tags: ['dunglas_angular_csrf.token_generator']
Event Listeners:
Listen to dunglas_angular_csrf.token_generated to log or modify tokens:
// src/EventListener/CsrfTokenListener.php
class CsrfTokenListener {
public function onTokenGenerated(TokenGeneratedEvent $event) {
// Custom logic here
}
}
Register the listener:
services:
App\EventListener\CsrfTokenListener:
tags:
- { name: 'kernel.event_listener', event: 'dunglas_angular_csrf.token_generated' }
How can I help you explore Laravel packages today?