diff --git a/docs/versioned_docs/version-2.0/Guides/integrating.md b/docs/versioned_docs/version-2.0/Guides/integrating.md
new file mode 100644
index 0000000..9f86439
--- /dev/null
+++ b/docs/versioned_docs/version-2.0/Guides/integrating.md
@@ -0,0 +1,158 @@
+---
+title: Integrating into applications
+---
+
+LmcRbac can be used in your application to implement role-based access control.
+
+However, it is important to note that Authorization service `isGranted()` method expects
+an identity to be provided. The identity must also implement the `Lmc\Rbac\Identity\IdentityInterface`.
+
+User authentication is not in the scope of LmcRbac and must be implemented by your application.
+
+## Laminas MVC applications
+
+In a Laminas MVC application, you can use the ['laminas-authentication'](https://docs.laminas.dev/laminas-authentication)
+component with an appropriate adapter to provide the identity.
+
+The `Laminas\Authentication\AuthenticationService` service provides the identity using the `getIdentity()` method.
+However, it is not prescriptive on the signature of the returned identity object. It is up to the
+authentication adapter to return a authentication result that contains an identity object that implements the
+`IdentityInterface`.
+
+For example:
+
+```php
+authenticationService = $authenticationService;
+ $this->authorizationService = $authorizationService;
+ }
+
+ public function doSomething()
+ {
+ $identity = $this->authenticationService->hasIdentity() ? $this->authenticationService->getIdentity() : null;
+
+ // Check for permission
+ if ($this->getAuthorizationService()->isGranted($identity, 'somepermssion')) {
+ // authorized
+ } else {
+ // not authorized
+ }
+ }
+
+}
+
+```
+### Other Laminas MVC components to use
+To facilitate integration in an MVC application, you can use [LmcUser](https://lm-commons.github.io/LmcUser/) for
+authentication.
+
+You can also use [LmcRbacMvc](https://lm-commons.github.io/LmcRbacMvc/) which extends LmcRbac by handling identities.
+It also provides additional functionalities like route guards and strategies for handling unauthorized access. For example,
+an unauthorized strategy could be to redirect to a login page.
+
+## Mezzio and PSR-7 applications
+
+In a Mezzio application, you can use the [`mezzio/mezzio-authentication`](https://docs.mezzio.dev/mezzio-authentication/)
+component to provide the identity. `mezzio/mezzio-authentication` will add a `UserInterface` object to the request attributes.
+
+Although the `UserInterface` interface has a `getRoles` method, LmcRbac's `AuthorizationService` still expects the identity
+to implement the `IdentityInterface`.
+
+This can be overcome by providing `mezzio/mezzio-authentication` with a custom factory to instantiate a user object that
+implements the `IdentityInterface` as explained in this [section](https://docs.mezzio.dev/mezzio-authentication/v1/intro/)
+of the `mezzio/mezzio-authentication` documentation.
+
+For example:
+
+```php
+identity = $identity;
+ $this->roles = $roles;
+ $this->details = $details;
+ }
+
+ public function getIdentity(): string
+ {
+ return $this->identity;
+ }
+
+ public function getRoles(): array
+ {
+ return $this->roles;
+ }
+
+ public function getDetails(): array
+ {
+ return $this->details;
+ }
+
+ public function getDetail(string $name, $default = null)
+ {
+ return $this->details[$name] ?? $default;
+ }
+}
+```
+Then provide a factory for creating the user class somewhere in a config provider:
+```php
+ [
+ UserInterface => function (string $identity, array $roles = [], array $details = []): UserInterface {
+ return new MyUser($identity, $roles, $details);
+ };
+ ],
+ ];
+
+```
+
+From this point, assuming that you have configured your application to use the `Mezzio\Authentication\AuthenticationMiddleware`,
+you can use `MyUser` in your handler by retrieving it from the request:
+
+```php
+// Retrieve the UserInterface object from the request.
+$user = $request->getAttribute(UserInterface::class);
+
+// Check for permission, this works because $user implements IdentityInterface
+if ($this->getAuthorizationService()->isGranted($user, 'somepermssion')) {
+ // authorized
+} else {
+ // not authorized
+}
+```
+
+How you define roles and permissions in your application is up to you. One way would be to use the route name as
+a permission such that authorization can be set up based on routes and optionally on route+verb.
+
+
+### Other Mezzio components to use
+
+A LmcRbac Mezzio component is under development to provide factories and middleware to facilitate integration of LmcRbac
+in Mezzio applications.
diff --git a/docs/versioned_docs/version-2.0/Upgrading/migration.md b/docs/versioned_docs/version-2.0/Upgrading/migration.md
new file mode 100644
index 0000000..b582938
--- /dev/null
+++ b/docs/versioned_docs/version-2.0/Upgrading/migration.md
@@ -0,0 +1,22 @@
+---
+sidebar_label: From ZF-Commons Rbac v3
+sidebar_position: 2
+title: Migrating from ZF-Commons RBAC v3
+---
+
+The ZF-Commons Rbac was created for the Zend Framework. When the Zend Framework was migrated to
+the Laminas project, the LM-Commons organization was created to provide components formerly provided by ZF-Commons.
+
+When ZfcRbac was moved to LM-Commons, it was split into two repositories:
+
+- [LmcRbacMvc](https://github.com/LM-Commons/LmcRbacMvc) contains the old version 2 of ZfcRbac.
+- LmcRbac contains the version 3 of ZfcRbac, which was only released as v3.alpha.1.
+
+To upgrade to LmcRbac v2, it is suggested to do it in two steps:
+
+1. Upgrade to LmcRbac v1 with the following steps:
+ * Uninstall `zf-commons/zfc-rbac:3.0.0-alpha.1`.
+ * Install `lm-commons/lmc-rbac:~1.0`
+ * Change `zfc-rbac.global.php` to `lmcrbac.global.php` and update the key `zfc_rbac` to `lmc_rbac`.
+ * Review your code for usages of the `ZfcRbac/*` namespace to `LmcRbac/*` namespace.
+2. Upgrade to LmcRbac v2 using the instructions in this [section](to-v2.md).
diff --git a/docs/versioned_docs/version-2.0/Upgrading/to-v2.md b/docs/versioned_docs/version-2.0/Upgrading/to-v2.md
new file mode 100644
index 0000000..c43c345
--- /dev/null
+++ b/docs/versioned_docs/version-2.0/Upgrading/to-v2.md
@@ -0,0 +1,37 @@
+---
+sidebar_label: From v1 to v2
+sidebar_position: 1
+title: Upgrading from v1 to v2
+---
+
+LmcRbac v2 is a major version upgrade with many breaking changes that prevent
+straightforward upgrading.
+
+### Namespace change
+
+The namespace has been changed from LmcRbac to Lmc\Rbac.
+
+Please review your code to replace references to the `LmcRbac` namespace
+by the `Lmc\Rbac` namespace.
+
+### LmcRbac is based on laminas-permissions-rbac
+
+LmcRbac is now based on the role class and interface provided by laminas-permissions-rbac which
+provides a hierarchical role model only.
+
+Therefore the `Role`, `HierarchicalRole` classes and the `RoleInterface` and `HierarchicalRoleInterface` have been removed
+in version 2.
+
+The `PermissionInterface` interface has been removed as permissions in `laminas-permissions-rbac` as just strings or any
+objects that can be casted to a string. If you use objects to hold permissions, just make sure that the object can be
+casted to a string by, for example, implementing a `__toString()` method.
+
+### Refactoring the factories
+
+The factories for services have been refactored from the `LmcRbac\Container` namespace
+to be colocated with the service that a factory is creating. All factories in the `LmcRbac\Container` namespace have
+been removed.
+
+### Refactoring the Assertion Plugin Manager
+
+The `AssertionContainer` class, interface and factory have been replaced by `AssertionPluginManager` class, interface and factory.
diff --git a/docs/versioned_docs/version-2.0/assertions.md b/docs/versioned_docs/version-2.0/assertions.md
new file mode 100644
index 0000000..dc86f1a
--- /dev/null
+++ b/docs/versioned_docs/version-2.0/assertions.md
@@ -0,0 +1,153 @@
+---
+sidebar_label: Dynamic Assertions
+sidebar_position: 6
+title: Dynamic Assertions
+---
+
+Dynamic Assertions provide the capability to perform extra validations when
+the authorization service's `isGranted()` method is called.
+
+As described in [Authorization Service](authorization-service#reference), it is possible to pass a context to the
+`isGranted()` method. This context is then passed to dynamic assertion functions. This context can be any object type.
+
+You can define dynamic assertion functions and assigned them to permission via configuration.
+
+## Defining a dynamic assertion function
+
+A dynamic assertion must implement the `Lmc\Rbac\Assertion\AssertionInterace` which defines only one method:
+
+```php
+public function assert(
+ string $permission,
+ ?IdentityInterface $identity = null,
+ mixed $context = null
+ ): bool
+```
+The assertion returns `true` when the access is granted, `false` otherwise.
+
+A simple assertion could be to check that user represented by `$identity`, for the permission
+represented by `$permission` owns the resource represented by `$context`.
+
+```php
+getOwnerId() === $identity->getId();
+ }
+ // This should not happen since this assertion should only be
+ // called when the 'edit' permission is checked
+ return true;
+ }
+}
+```
+## Configuring Assertions
+
+Dynamic assertions are configured in LmcRbac via an assertion map defined in the LmcRbac configuration where assertions
+are associated with permissions.
+
+The `assertion_map` key in the configuration is used to define the assertion map. If an assertion needs to be created via
+a factory, use the `assertion_manager` config key. The Assertion Manager is a standard
+plugin manager and its configuration should be a service manager configuration array.
+
+```php
+ [
+ /* the rest of the file */
+ 'assertion_map' => [
+ 'edit' => \My\Namespace\MyAssertion::class,
+ ],
+ 'assertion_manager' => [
+ 'factories' => [
+ \My\Namespace\MyAssertion::class => InvokableFactory::class
+ ],
+ ],
+ ],
+];
+```
+It is also possible to configure an assertion using a callable instead of a class:
+
+```php
+ [
+ /* the rest of the file */
+ 'assertion_map' => [
+ 'edit' => function assert(string $permission, ?IdentityInterface $identity = null, $context = null): bool
+ {
+ // for 'edit' permission
+ if ('edit' === $permission) {
+ /** @var MyObjectClass $context */
+ return $context->getOwnerId() === $identity->getId();
+ }
+ // This should not happen since this assertion should only be
+ // called when the 'edit' permission is checked
+ return true;
+ },
+ ],
+ ],
+];
+```
+## Dynamic Assertion sets
+
+LmcRbac supports the creation of dynamic assertion sets where multiple assertions can be combined using 'and/or' logic.
+Assertion sets are configured by associating an array of assertions to a permission in the assertion map:
+
+```php
+ [
+ /* the rest of the file */
+ 'assertion_map' => [
+ 'edit' => [
+ \My\Namespace\AssertionA::class,
+ \My\Namespace\AssertionB::class,
+ ],
+ 'read' => [
+ 'condition' => \Lmc\Rbac\Assertion\AssertionSet::CONDITION_OR,
+ \My\Namespace\AssertionC::class,
+ \My\Namespace\AssertionD::class,
+ ],
+ 'delete' => [
+ 'condition' => \Lmc\Rbac\Assertion\AssertionSet::CONDITION_OR,
+ \My\Namespace\AssertionE::class,
+ [
+ 'condition' => \Lmc\Rbac\Assertion\AssertionSet::CONDITION_AND,
+ \My\Namespace\AssertionF::class,
+ \My\Namespace\AssertionC::class,
+ ],
+ ],
+ /** the rest of the file */
+ ],
+];
+```
+By default, an assertion set combines assertions using a 'and' condition. This is demonstrated by the map associated with
+the `'edit'` permission above.
+
+It is possible to combine assertions using a 'or' condition by adding a `condition` equal to `AssertionSet::CONDITION_OR`
+to the assertion set as demonstrated by the map associated with the `'read'` permission above.
+
+Furthermore, it is possible to nest assertion sets in order to create more complex logic as demonstrated by the map
+associated with the `'delete'` permission above.
+
+The default logic is to combine assertions using 'and' logic but this can be explicitly set as shown above for `'delete'`
+permission.
+
+## Defining dynamic assertions at run-time
+
+Although dynamic assertions are typically defined in the application's configuration, it is possible to set
+dynamic assertions at run-time by using the Authorization Service utility methods for adding/getting assertions.
+
+These methods are described in the Authorization Service [reference](authorization-service.md#reference).
diff --git a/docs/versioned_docs/version-2.0/authorization-service.md b/docs/versioned_docs/version-2.0/authorization-service.md
new file mode 100644
index 0000000..ee68543
--- /dev/null
+++ b/docs/versioned_docs/version-2.0/authorization-service.md
@@ -0,0 +1,166 @@
+---
+sidebar_label: Authorization service
+sidebar_position: 5
+title: Authorization Service
+---
+
+### Usage
+
+The Authorization service can be retrieved from the service manager using the name
+`Lmc\Rbac\Service\AuthorizationServiceInterface` and injected into your code:
+
+```php
+get(Lmc\Rbac\Service\AuthorizationServiceInterface::class);
+
+```
+### Reference
+
+`Lmc\Rbac\Service\AuthorizationServiceInterface` defines the following methods:
+
+#### `isGranted(?IdentityInterface $identity, string $permission, $context = null): bool`
+
+Checks that the identity has is granted the permission for the (optional) context.
+
+ | Parameter | Description |
+ |----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+ | `$identity` | The identity whose roles to checks. If `$identity` is null, then the `guest` is used. The `guest` role is definable via configuration and defaults to `'guest'`. |
+ | `$permission` | The permission to check against |
+ | `$context` | A context that will be passed to dynamic assertions that are defined for the permission |
+
+#### `setAssertions(array $assertions, bool $merge = false): void`
+
+Allows to define dynamic assertions at run-time.
+
+ | Parameter | Description |
+ |---------------|-----------------------------------------------------------------------------------------|
+ | `$assertions` | An array of assertions to merge or to replace |
+ | `$merge` | if `true` the content of `$assertions` will be merged with existing assertions. |
+
+
+#### `setAssertion(string $permission, AssertionInterface|callable|string $assertion): void`
+Allows to define a dynamic assertion at run-time.
+
+ | Parameter | Description |
+ |---------------|-----------------------------------------|
+ | `$permission` | Permission name |
+ | `$assertion` | The assertion to set for `$permission` |
+
+#### `hasAssertion(string $permission): bool`
+Checks if the authorization has a dynamic assertion for a given permission.
+
+ | Parameter | Description |
+ |---------------|--------------------------|
+ | `$permission` | Permission name |
+
+
+#### `getAssertions(): array`
+
+Returns all the dynamic assertions defined.
+
+#### `getAssertion(string $permission): AssertionInterface|callable|string|null`
+
+Returns the dynamic assertion for the give permission
+
+ | Parameter | Description |
+ |---------------|-----------------------------|
+ | `$permission` | Permission permission name |
+
+More on dynamic assertions can be found in the [Assertions](assertions.md) section.
+
+More on the `guest` role can be found in the [Configuration](configuration.md) section.
+
+## Injecting the Authorization Service
+
+There are a few methods to inject the Authorization Service into your service.
+
+### Using a factory
+
+You can inject the AuthorizationService into your own objects using a factory. The Authorization Service
+can be retrieved from the container using `'Lmc\Rbac\Service\AuthorizationServiceInterface'`.
+
+Here is a classic example for injecting the Authorization Service into your own service
+
+*in your app's Module*
+
+```php
+use Lmc\Rbac\Service\AuthorizationServiceInterface;
+class Module
+{
+ public function getConfig()
+ {
+ return [
+ 'service_manager' => [
+ 'factories' => [
+ 'MyService' => function($sm) {
+ $authService = $sm->get('AuthorizationServiceInterface');
+ return new MyService($authService);
+ }
+ ],
+ ],
+ ];
+ }
+}
+````
+
+### Using traits
+
+For convenience, LmcRbac provides a `AuthorizationServiceAwareTrait` that adds the `$authorizationService` property and
+setter/getter methods.
+
+### Using delegators
+
+LmcRbac ships with a `Lmc\Rbac\Service\AuthorizationServiceDelegatorFactory` [delegator factory](https://docs.laminas.dev/laminas-servicemanager/delegators/)
+to automatically inject the authorization service into your classes.
+
+Your class must implement the `Lmc\Rbac\Service\AuthorizationServiceAwareInterface` and use the above trait, as shown below:
+
+```php
+namespace MyModule;
+
+use Lmc\Rbac\Service\AuthorizationServiceAwareInterface;
+use Lmc\Rbac\Service\AuthorizationServiceAwareTrait;
+
+class MyClass implements AuthorizationServiceAwareInterface
+{
+ use AuthorizationServiceAwareTrait;
+
+ public function doSomethingThatRequiresAuth()
+ {
+ if (! $this->getAuthorizationService()->isGranted($identity, 'deletePost')) {
+ throw new \Exception('You are not allowed !');
+ }
+ return true;
+ }
+}
+```
+
+And add your class to the right delegator:
+
+```php
+namespace MyModule;
+use Lmc\Rbac\Service\AuthorizationServiceDelegatorFactory;
+class Module
+{
+ // ...
+
+ public function getConfig()
+ {
+ return [
+ 'service_manager' => [
+ 'factories' => [
+ MyClass::class => InvokableFactory::class,
+ ],
+ 'delegators' => [
+ MyClass::class => [
+ AuthorizationServiceDelegatorFactory::class,
+ ],
+ ],
+ ],
+ ];
+ }
+}
+```
+
+
diff --git a/docs/versioned_docs/version-2.0/configuration.md b/docs/versioned_docs/version-2.0/configuration.md
new file mode 100644
index 0000000..7d94088
--- /dev/null
+++ b/docs/versioned_docs/version-2.0/configuration.md
@@ -0,0 +1,19 @@
+---
+sidebar_label: Configuration
+sidebar_position: 7
+title: Configuring LmcRbac
+---
+
+LmcRbac is configured via the `lmc_rbac` key in the application config.
+
+This is typically achieved by creating
+a `config/autoload/lmcrbac.global.php` file. A sample configuration file is provided in the `config/` folder.
+
+## Reference
+
+| Key | Description |
+|--|------------------------------------------------------------------------------------------------------------------------------------------------|
+| `guest_role` | Defines the name of the `guest` role when no identity exists. Defaults to `'guest'`. |
+| `role_provider` | Defines the role provider. Defaults to `[]` See the [Role Providers](role-providers) section. |
+| `assertion_map` | Defines the dynamic assertions that are associated to permissions. Defaults to `[]`. See the [Dynamic Assertions](assertions) section. |
+| `assertion_manager` | Provides a configuration for the Assertion Plugin Manager. Defaults to `[]`. See the [Dynamic Assertion](assertions.md) section. |
diff --git a/docs/versioned_docs/version-2.0/quick-start.md b/docs/versioned_docs/version-2.0/quick-start.md
new file mode 100644
index 0000000..3789ebc
--- /dev/null
+++ b/docs/versioned_docs/version-2.0/quick-start.md
@@ -0,0 +1,197 @@
+---
+title: Quick Start
+sidebar_position: 1
+---
+
+LmcRbac offers components and services to implement role-based access control (RBAC) in your application.
+LmcRbac extends the components provided by [laminas-permissions-rbac](https://github.com/laminas/laminas-permissions-rbac).
+
+LmcRbac can be used in Laminas MVC and in Mezzio applications.
+
+:::tip
+If you are upgrading from LmcRbac v1 or from zfc-rbac v3, please read the [Upgrading section](Upgrading/to-v2.md)
+:::
+
+## Concepts
+
+[Role-Based Access Control (RBAC)](https://en.wikipedia.org/wiki/Role-based_access_control)
+is an approach to restricting system access to authorized users by putting emphasis
+on roles and their permissions.
+
+In the RBAC model:
+
+- an **identity** has one of more roles.
+- a **role** has one of more permissions.
+- a **permission** is typically an action like "read", "write", "delete".
+- a **role** can have **child roles** thus providing a hierarchy of roles where a role will inherit the permissions of all its child roles.
+
+### Authorization
+
+An identity will be authorized to perform an action, such as accessing a resource, if it is granted
+the permission that controls the execution of the action.
+
+For example, deleting an item could be restricted to identities that have at least one role that has the
+`item.delete` permission. This could be implemented by defining a `member` role that has the `item.delete` and assigning
+this role of an authenticated user.
+
+### Dynamic Assertions
+
+In some cases, just checking if the identity has the `item.delete` permission is not enough.
+It would also be necessary to check, for example, that the `item` belongs to the identity. Dynamic assertion allow
+to specify some extra checks before granting access to perform an action such as, in this case, being the owner of the
+resource.
+
+### Identities
+
+An identity is typically provided by an authentication process within the application.
+
+Authentication is not in the scope of `LmcRbac` and it is assumed that an identity entity that can provide the assigned
+roles is available when using the authorization service. If no identity is available, as it would be the case when no
+user is "logged in", then a guest role is assumed.
+
+## Requirements
+
+- PHP 8.1 or higher
+
+## Installation
+
+LmcRbac only officially supports installation through Composer.
+
+Install the module:
+
+```sh
+$ composer require lm-commons/lmc-rbac "~1.0"
+```
+
+You will be prompted by the `laminas-component-installer` plugin to inject LM-Commons\LmcRbac.
+
+:::note
+**Manual installation:**
+
+Enable the module by adding `Lmc\Rbac` key to your `application.config.php` or `modules.config.php` file for Laminas MVC
+applications, or to the `config/config.php` file for Mezzio applications.
+:::
+
+Customize the module by copy-pasting
+the `lmcrbac.global.php` file to your `config/autoload` folder.
+
+:::note
+On older versions of `LmcRbac`, the configuration file is named `config/config.global.php`.
+:::
+
+## Defining roles
+
+By default, no roles and no permissions are defined.
+
+Roles and permissions are defined by a Role Provider. `LmcRbac` ships with two roles providers:
+- a simple `InMemoryRoleProvider` that uses an associative array to define roles and their permission. This is the default.
+- a `ObjectRepositoyRoleProvider` that is based on Doctrine ORM.
+
+To quickly get started, let's use the `InMemoryRoleProvider` role provider.
+
+In the `config/autoload/lmcrbac.global.php`, add the following:
+
+```php
+ [
+ 'role_provider' => [
+ Lmc\Rbac\Role\InMemoryRoleProvider::class => [
+ 'guest',
+ 'user' => [
+ 'permissions' => ['create', 'edit'],
+ ],
+ 'admin' => [
+ 'children' => ['user'],
+ 'permissions' => ['delete'],
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+This defines 3 roles: a `guest` role, a `user` role having 2 permissions, and a `admin` role which has the `user` role as
+a child and with its own permission. If the hierarchy is flattened:
+
+- `guest` has no permission
+- `user` has permissions `create` and `edit`
+- `admin` has permissions `create`, `edit` and `delete`
+
+## Basic authorization
+
+The authorization service can get retrieved from the service manager container and used to check if a permission
+is granted to an identity:
+
+```php
+get('\Lmc\Rbac\Service\AuthorizationServiceInterface');
+
+ /** @var \Lmc\Rbac\Identity\IdentityInterface $identity */
+ if ($authorizationService->isGranted($identity, 'create')) {
+ /** do something */
+ }
+```
+
+If `$identity` has the role `user` and/or `admin` then the authorization is granted. If the identity has the role `guest`, then authorization
+is denied.
+
+:::info
+If `$identity` is null (no identity), then the guest role is assumed which is set to `'guest'` by default. The guest role
+can be configured in the `lmcrbac.config.php` file. More on this in the [Configuration](configuration.md) section.
+:::
+
+:::warning
+`LmcRbac` does not provide any logic to instantiate an identity entity. It is assumed that
+the application will instantiate an entity that implements `\Lmc\Rbac\Identity\IdentityInterface` which defines the `getRoles()`
+method.
+:::
+
+## Using assertions
+
+Even if an identity has the `user` role granting it the `edit` permission, it should not have the authorization to edit another identity's resource.
+
+This can be achieved using dynamic assertion.
+
+An assertion is a function that implements the `\Lmc\Rbac\Assertion\AssertionInterface` and is configured in the configuration
+file.
+
+Let's modify the `lmcrbac.config.php` file as follows:
+
+```php
+ [
+ 'role_provider' => [
+ /* roles and permissions
+ ],
+ 'assertion_map' => [
+ 'edit' => function ($permission, IdentityInterface $identity = null, $resource = null) {
+ if ($resource->getOwnerId() === $identity->getId() {
+ return true;
+ } else {
+ return false;
+ }
+ ],
+ ],
+];
+```
+
+Then use the authorization service passing the resource (called a 'context') in addition to the permission:
+
+```php
+get('\Lmc\Rbac\Service\AuthorizationServiceInterface');
+
+ /** @var \Lmc\Rbac\Identity\IdentityInterface $identity */
+ if ($authorizationService->isGranted($identity, 'edit', $resource)) {
+ /** do something */
+ }
+```
+
+Dynanmic assertions are further discussed in the [Dynamic Assertions](assertions) section.
diff --git a/docs/versioned_docs/version-2.0/role-providers.md b/docs/versioned_docs/version-2.0/role-providers.md
new file mode 100644
index 0000000..a011763
--- /dev/null
+++ b/docs/versioned_docs/version-2.0/role-providers.md
@@ -0,0 +1,219 @@
+---
+sidebar_label: Roles, permissions and Role providers
+title: Roles, Permissions and Role providers
+sidebar_position: 4
+---
+
+## Roles
+
+A role is an object that returns a list of permissions that the role has.
+
+LmcRbac uses the Role class defined by [laminas-permissions-rbac](https://github.com/laminas/laminas-permissions-rbac).
+
+Roles are defined using by the `\Laminas\Permissions\Rbac\Role` class or by a class
+implementing `\Laminas\Permissions\Rbac\RoleInterface`.
+
+Roles can have child roles and therefore provides a hierarchy of roles where a role inherit the permissions of all its
+child roles.
+
+For example, a 'user' role may have the 'read' and 'write' permissions, and a 'admin' role
+may inherit the permissions of the 'user' role plus an additional 'delete' role. In this structure,
+the 'admin' role will have 'user' as its child role.
+
+
+:::tip[Flat roles]
+Previous version of LmcRbac used to make a distinction between flat roles and hierarchical roles.
+A flat role is just a simplification of a hierarchical role, i.e. a hierarchical role without children.
+
+In `laminas-permissions-rbac`, roles are hierarchical.
+:::
+
+## Permissions
+
+A permission in `laminas-permissions-rbac` is simply a string that represents the permission such as 'read', 'write' or 'delete'.
+But it can also be more precise like 'article.read' or 'article.write'.
+
+A permission can also be an object as long as it can be casted to a string. This could be the
+case, for example, when permissions are stored in a database where they could also have a identified and a description.
+
+:::tip
+An object can be casted to a string by implementing the `__toString()` method.
+:::
+
+## Role Providers
+A role provider is an object that returns a list of roles. A role provider must implement the
+`Lmc\Rbac\Role\RoleProviderInterface` interface. The only required method is `getRoles`, and must return an array
+of `Laminas\Permissions\Rbac\RoleInterface` objects.
+
+Roles can come from one of many sources: in memory, from a file, from a database, etc. However, you can specify only one role provider per application.
+
+### Built-in role providers
+
+LmcRbac comes with two built-in role providers: `Lmc\Rbac\Role\InMemoryRoleProvider` and
+`Lmc\Rbac\Role\ObjectRepositoryRoleProvider`. A role provider must be added to the `role_provider` subkey in the
+configuration file. For example:
+
+```php
+return [
+ 'lmc_rbac' => [
+ 'role_provider' => [
+ Lmc\Rbac\Role\InMemoryRoleProvider::class => [
+ // configuration
+ ],
+ ]
+ ]
+];
+```
+
+### `Lmc\Rbac\Role\InMemoryRoleProvider`
+
+This provider is ideal for small/medium sites with few roles/permissions. All the data is specified in a simple associative array in a
+PHP file.
+
+Here is an example of the format you need to use:
+
+```php
+return [
+ 'lmc_rbac' => [
+ 'role_provider' => [
+ Lmc\Rbac\Role\InMemoryRoleProvider::class => [
+ 'admin' => [
+ 'children' => ['member'],
+ 'permissions' => ['article.delete']
+ ],
+ 'member' => [
+ 'children' => ['guest'],
+ 'permissions' => ['article.edit', 'article.archive']
+ ],
+ 'guest' => [
+ 'permissions' => ['article.read']
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+The `children` and `permissions` subkeys are entirely optional. Internally, the `Lmc\Rbac\Role\InMemoryRoleProvider` creates
+`Lmc\Rbac\Role\Role` objects with children, if any.
+
+If you are more confident with flat RBAC, the previous config can be re-written to remove any inheritence between roles:
+
+```php
+return [
+ 'lmc_rbac' => [
+ 'role_provider' => [
+ Lmc\Rbac\Role\InMemoryRoleProvider::class => [
+ 'admin' => [
+ 'permissions' => [
+ 'article.delete',
+ 'article.edit',
+ 'article.archive',
+ 'article.read'
+ ]
+ ],
+ 'member' => [
+ 'permissions' => [
+ 'article.edit',
+ 'article.archive',
+ 'article.read'
+ ]
+ ],
+ 'guest' => [
+ 'permissions' => ['article.read']
+ ]
+ ]
+ ]
+ ]
+];
+```
+
+### `Lmc\Rbac\Role\ObjectRepositoryRoleProvider`
+
+This provider fetches roles from a database using `Doctrine\Common\Persistence\ObjectRepository` interface.
+
+You can configure this provider by giving an object repository service name that is fetched from the service manager
+using the `object_repository` key:
+
+```php
+return [
+ 'lmc_rbac' => [
+ 'role_provider' => [
+ Lmc\Rbac\Role\ObjectRepositoryRoleProvider::class => [
+ 'object_repository' => 'App\Repository\RoleRepository',
+ 'role_name_property' => 'name'
+ ],
+ ],
+ ],
+];
+```
+
+Or you can specify the `object_manager` and `class_name` options:
+
+```php
+return [
+ 'lmc_rbac' => [
+ 'role_provider' => [
+ Lmc\Rbac\Role\ObjectRepositoryRoleProvider::class => [
+ 'object_manager' => 'doctrine.entitymanager.orm_default',
+ 'class_name' => 'App\Entity\Role',
+ 'role_name_property' => 'name'
+ ],
+ ],
+ ],
+];
+```
+
+In both cases, you need to specify the `role_name_property` value, which is the name of the entity's property
+that holds the actual role name. This is used internally to only load the identity roles, instead of loading
+the whole table every time.
+
+Please note that your entity fetched from the table MUST implement the `Lmc\Rbac\Role\RoleInterface` interface.
+
+Sample ORM entity models are provided in the `/data` folder for flat role, hierarchical role and permission.
+
+## Creating custom role providers
+
+To create a custom role provider, you first need to create a class that implements the
+`Lmc\Rbac\Role\RoleProviderInterface` interface.
+
+Then, you need to add it to the role provider manager:
+
+```php
+return [
+ 'lmc_rbac' => [
+ 'role_provider' => [
+ MyCustomRoleProvider::class => [
+ // Options
+ ],
+ ],
+ ],
+];
+```
+And the role provider is created using the service manager:
+```php
+return [
+ 'service_manager' => [
+ 'factories' => [
+ MyCustomRoleProvider::class => MyCustomRoleProviderFactory::class,
+ ],
+ ],
+];
+```
+
+## Role Service
+
+LmcRbac provides a role service that will use the Role Providers to provide the roles
+associated with a given identity.
+
+It can be retrieved from the container be requesting the `Lmc\Rbac\Service\RoleServiceIntgeface`.
+
+`Lmc\Rbac\Service\RoleServiceInterface` defines the following method:
+
+- `getIdentityRoles(?IdentityInterface $identity = null): iterable`
+
+ | Parameter | Description |
+ |----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+ | `$identity` | The identity whose roles to retrieve. If `$identity` is null, then the `guest` is used. The `guest` role is definable via configuration and defaults to `'guest'`. |
+
+
diff --git a/docs/versioned_sidebars/version-2.0-sidebars.json b/docs/versioned_sidebars/version-2.0-sidebars.json
new file mode 100644
index 0000000..5f41a72
--- /dev/null
+++ b/docs/versioned_sidebars/version-2.0-sidebars.json
@@ -0,0 +1,8 @@
+{
+ "documentationSidebar": [
+ {
+ "type": "autogenerated",
+ "dirName": "."
+ }
+ ]
+}
diff --git a/docs/versions.json b/docs/versions.json
index df2d553..904ff97 100644
--- a/docs/versions.json
+++ b/docs/versions.json
@@ -1,3 +1,4 @@
[
+ "2.0",
"1.4"
]