Integrate API Platform security
Edit on GitHubThis document describes how to integrate Symfony’s SecurityBundle with the API Platform to enable authentication and authorization for your API resources.
Prerequisites
- API Platform is already integrated as described in Integrate API Platform.
- The
spryker/api-platformmodule version1.0.0or later is installed.
1. Register the SecurityBundle
Add SecurityBundle to the bundles.php file for each Glue application where you want to enable security.
For Glue application
config/Glue/bundles.php
<?php
declare(strict_types = 1);
use ApiPlatform\Symfony\Bundle\ApiPlatformBundle;
use Spryker\ApiPlatform\SprykerApiPlatformBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
use Symfony\Bundle\TwigBundle\TwigBundle;
return [
FrameworkBundle::class => ['all' => true],
SecurityBundle::class => ['all' => true],
TwigBundle::class => ['all' => true],
ApiPlatformBundle::class => ['all' => true],
SprykerApiPlatformBundle::class => ['all' => true],
];
For GlueStorefront application
config/GlueStorefront/bundles.php
<?php
declare(strict_types = 1);
use ApiPlatform\Symfony\Bundle\ApiPlatformBundle;
use Spryker\ApiPlatform\SprykerApiPlatformBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
use Symfony\Bundle\TwigBundle\TwigBundle;
return [
FrameworkBundle::class => ['all' => true],
SecurityBundle::class => ['all' => true],
TwigBundle::class => ['all' => true],
ApiPlatformBundle::class => ['all' => true],
SprykerApiPlatformBundle::class => ['all' => true],
];
For GlueBackend application
config/GlueBackend/bundles.php
<?php
declare(strict_types = 1);
use ApiPlatform\Symfony\Bundle\ApiPlatformBundle;
use Spryker\ApiPlatform\SprykerApiPlatformBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
use Symfony\Bundle\TwigBundle\TwigBundle;
return [
FrameworkBundle::class => ['all' => true],
SecurityBundle::class => ['all' => true],
TwigBundle::class => ['all' => true],
ApiPlatformBundle::class => ['all' => true],
SprykerApiPlatformBundle::class => ['all' => true],
];
SecurityBundle must be registered before ApiPlatformBundle and SprykerApiPlatformBundle so that the security services are available when API Platform compiles its configuration.
2. Configure the security firewall
Create a security.php configuration file for each Glue application. This file defines the authentication provider, firewall, and default access control.
For Glue application
config/Glue/packages/security.php
<?php
declare(strict_types=1);
use Spryker\ApiPlatform\Security\ApiUserProvider;
use Spryker\ApiPlatform\Security\GlueAuthenticationEntryPoint;
use Spryker\ApiPlatform\Security\OauthAuthenticator;
use Symfony\Config\SecurityConfig;
return static function (SecurityConfig $security): void {
$security->provider('api_oauth_provider')
->id(ApiUserProvider::class);
$security->firewall('main')
->lazy(true)
->stateless(true)
->provider('api_oauth_provider')
->customAuthenticators([OauthAuthenticator::class])
->entryPoint(GlueAuthenticationEntryPoint::class);
// Public by default - individual resources use security expressions for authorization
$security->accessControl()
->path('^/')
->roles(['PUBLIC_ACCESS']);
};
For GlueStorefront application
config/GlueStorefront/packages/security.php
Use the same configuration as above.
For GlueBackend application
config/GlueBackend/packages/security.php
Use the same configuration as above.
Configuration explained
| Setting | Description |
|---|---|
provider('api_oauth_provider') |
Registers the user provider that builds ApiUser objects from validated JWT claims. |
firewall('main')->lazy(true) |
The authenticator is only instantiated when a route requires authentication, reducing overhead for public endpoints. |
firewall('main')->stateless(true) |
Disables session-based authentication. Every request must include its own Bearer token. |
customAuthenticators([OauthAuthenticator::class]) |
Registers the Spryker OAuth authenticator that validates Bearer tokens using the local OAuth infrastructure. |
entryPoint(GlueAuthenticationEntryPoint::class) |
Returns the standard 403 Missing access token. error when an unauthenticated request hits a protected resource. |
accessControl()->roles(['PUBLIC_ACCESS']) |
Grants public access to all paths by default. Individual resources opt in to authentication using security expressions. |
3. Add security expressions to resources
After the SecurityBundle is configured, you can protect resources using security expressions in your YAML resource schemas, either for an entire resource or for specific operations. For the expression syntax, available variables, and examples, see API Platform security.
Regenerate resources
After adding security expressions, regenerate your API resources:
docker/sdk cli glue api:generate
4. Optional: Enable Persistent ACL for the Backend API
For tokens of Back Office and merchant users, the Backend API resolves the user behind the token and makes it the acting user of the request. To have Persistent ACL scope the requests of merchant users to their merchant the same way the Merchant Portal does, register the following plugins. Back Office users are not scoped, as in the Back Office. The scoping applies to API Platform resources only: legacy Glue resources run without an acting user, so Persistent ACL stays disabled for them.
| PLUGIN | SPECIFICATION | PREREQUISITES | NAMESPACE |
|---|---|---|---|
| AclEntityApplicationPlugin | Enables Persistent ACL for the Backend API application. | Spryker\Glue\AclEntity\Plugin\Application | |
| NoCurrentMerchantUserAclEntityDisablerPlugin | Disables Persistent ACL unless the acting user is a merchant user, so that Back Office users, userless requests like the token endpoint, and public endpoints are not filtered. | Spryker\Zed\MerchantUser\Communication\Plugin\AclEntity |
src/Pyz/Glue/GlueBackendApiApplication/GlueBackendApiApplicationDependencyProvider.php
<?php
namespace Pyz\Glue\GlueBackendApiApplication;
use Spryker\Glue\GlueBackendApiApplication\GlueBackendApiApplicationDependencyProvider as SprykerGlueBackendApiApplicationDependencyProvider;
use Spryker\Glue\AclEntity\Plugin\Application\AclEntityApplicationPlugin;
class GlueBackendApiApplicationDependencyProvider extends SprykerGlueBackendApiApplicationDependencyProvider
{
/**
* @return array<\Spryker\Shared\ApplicationExtension\Dependency\Plugin\ApplicationPluginInterface>
*/
protected function getApplicationPlugins(): array
{
return [
new AclEntityApplicationPlugin(),
];
}
}
src/Pyz/Zed/AclEntity/AclEntityDependencyProvider.php
<?php
namespace Pyz\Zed\AclEntity;
use Spryker\Zed\AclEntity\AclEntityDependencyProvider as SprykerAclEntityDependencyProvider;
use Spryker\Zed\MerchantUser\Communication\Plugin\AclEntity\NoCurrentMerchantUserAclEntityDisablerPlugin;
class AclEntityDependencyProvider extends SprykerAclEntityDependencyProvider
{
/**
* @return array<\Spryker\Zed\AclEntityExtension\Dependency\Plugin\AclEntityDisablerPluginInterface>
*/
protected function getAclEntityDisablerPlugins(): array
{
return [
new NoCurrentMerchantUserAclEntityDisablerPlugin(),
];
}
}
Authenticate as a merchant user and request a resource that is scoped by Persistent ACL, for example, GET /merchant-profile. Make sure the response contains only the data of the merchant the user is assigned to, that a Back Office user still reads the data of every merchant, and that POST /token still succeeds without an Authorization header.
5. Clear caches
Clear application caches after configuration changes:
docker/sdk cli console cache:clear
Verification
Verify SecurityBundle is registered
Check that the security services are available:
docker/sdk cli glue debug:container SecurityBundle
Test authentication
Send a request without a token to a protected resource — it should return 403 Forbidden with the Missing access token. error:
curl -s https://glue-storefront.your-domain/customers/DE--1 | jq .
Send a request with a valid Bearer token:
curl -s -H "Authorization: Bearer <your-jwt-token>" \
https://glue-storefront.your-domain/customers/DE--1 | jq .
Compile-time validation
If you add security expressions to resource schemas but forget to register the SecurityBundle, the application throws an error at compile time:
InvalidArgumentException: The following API resource schemas use security expressions
but SecurityBundle is not registered: customers, orders. Register SecurityBundle in
your bundles.php to enable security expression evaluation.
This validation is performed by the SecurityServiceRegistrationPass compiler pass.
Next steps
- Security - Understanding authentication and authorization
- Resource schemas - Security expression syntax
- API Platform configuration - Configuration options
Thank you!
For submitting the form