Integrate Persistent ACL for merchant API endpoints

Edit on GitHub

This document describes how to enable Persistent ACL for the Backend API so that merchant users see and change only the data of their merchant, the same way they do in the Merchant Portal.

With the API Platform integration, the Backend API resolves the user behind a Back Office or merchant user token and makes it the acting user of the request. Persistent ACL uses the acting user to filter database queries. After the integration described here, the following applies:

  • A merchant user reads and writes the data of the merchant it is assigned to only. Merchant-specific resources like the merchant profile return 404 or an empty collection for data of other merchants.
  • A Back Office user without a merchant is not scoped and reads the data of every merchant, as in the Back Office.
  • Requests without an acting user, such as POST /token and public endpoints, are not filtered.
API Platform only

The acting user of a request exists only in the API Platform integration of the Backend API. The legacy Glue infrastructure does not resolve the user behind a token, so Persistent ACL cannot scope legacy Glue resources; they stay unfiltered even after the plugins on this page are registered. Legacy Glue resources are protected by scopes and route rules instead. For details, see Use Backend API authorization scopes and Create protected Backend API endpoints.

Prerequisites

Install the required modules using Composer:

composer require spryker/acl-entity:"^1.18.0" spryker/merchant-user:"^1.10.0" --update-with-dependencies
MODULE MINIMUM VERSION PROVIDES
spryker/acl-entity ^1.18.0 The AclEntityApplicationPlugin for the Glue layer, which enables Persistent ACL in the Backend API application.
spryker/merchant-user ^1.10.0 The NoCurrentMerchantUserAclEntityDisablerPlugin, which limits the scoping to merchant users.

1. Enable Persistent ACL in the Backend API application

Persistent ACL is enabled per application. Register the Glue AclEntityApplicationPlugin in the Backend API application:

PLUGIN SPECIFICATION PREREQUISITES NAMESPACE
AclEntityApplicationPlugin Enables Persistent ACL for the Backend API application. Spryker\Glue\AclEntity\Plugin\Application

src/Pyz/Glue/GlueBackendApiApplication/GlueBackendApiApplicationDependencyProvider.php

<?php

namespace Pyz\Glue\GlueBackendApiApplication;

use Spryker\Glue\AclEntity\Plugin\Application\AclEntityApplicationPlugin;
use Spryker\Glue\GlueBackendApiApplication\GlueBackendApiApplicationDependencyProvider as SprykerGlueBackendApiApplicationDependencyProvider;

class GlueBackendApiApplicationDependencyProvider extends SprykerGlueBackendApiApplicationDependencyProvider
{
    /**
     * @return array<\Spryker\Shared\ApplicationExtension\Dependency\Plugin\ApplicationPluginInterface>
     */
    protected function getApplicationPlugins(): array
    {
        return [
            new AclEntityApplicationPlugin(),
        ];
    }
}
Zed plugin

The Zed layer ships its own Spryker\Zed\AclEntity\Communication\Plugin\Application\AclEntityApplicationPlugin, which the Back Office and the Merchant Portal register. The Backend API is a Glue application and needs the Glue plugin from the table above.

2. Limit the scoping to merchant users

Persistent ACL filters every query of a request once it is enabled for the application. To keep Back Office users and requests without an acting user unfiltered, register a disabler plugin that turns Persistent ACL off unless the acting user is a merchant user:

PLUGIN SPECIFICATION PREREQUISITES NAMESPACE
NoCurrentMerchantUserAclEntityDisablerPlugin Disables Persistent ACL when the current request has no acting user or the acting user is not assigned to a merchant. Spryker\Zed\MerchantUser\Communication\Plugin\AclEntity

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(),
        ];
    }
}
Disabler plugins apply to every application

Disabler plugins are evaluated wherever Persistent ACL is enabled, including the Merchant Portal. There, the acting user is always a merchant user, so the plugin does not change the Merchant Portal behavior. If your project already registers other disabler plugins, keep them in the list.

3. Clear caches

docker/sdk cli console cache:empty-all
Verification
  1. 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.
  2. Authenticate as a Back Office user without a merchant and request a resource that reads merchant data, for example, GET /merchant-profiles/{merchantReference} of several merchants. Make sure every merchant is returned.
  3. Send POST /token without an Authorization header. Make sure a token is issued.