# Access Control

### Components

Using Appmixer ACL feature you can control user or user groups access to connectors. This can be configured both from the [Appmixer Backoffice](https://docs.appmixer.com/appmixer-backoffice) or through the [API](https://docs.appmixer.com/api/acl#update-acl-rules).

If you open Appmixer Backoffice, you can see an ACL section in the left menu under the "System" menu. You can then choose between settings for *routes* and *components*.

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/kSTf1t4clCpE9UskhTrH/Appmixer_Backoffice_-_ACL.png)

When you open the *components* section, you can see the default ACL rules. Users with the scope *admin, user* and *tester* can use all *non-private* components. Components can be hidden using the [*private*](https://docs.appmixer.com/tutorials/broken-reference) property defined in the component manifest file. You can decide to make these private components visible to certain user groups using ACL.&#x20;

The default ACL setting you will see loos like this:

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/RcsImKOlR3c55HB4Crp1/Appmixer_Backoffice_-_ACL.png)

If you want to set different ACL rules for different connectors, start with deleting the general rule that allows all users to access all components. If you did not do this step, the rule `user - * - *` would overrule any other rule you would create for the *user* scope.&#x20;

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/gws5zZLTyqLt06KNaAJA/Appmixer_Backoffice_-_ACL.png)

After deleting the above mentioned generic rule, you'll notice that the Appmixer Flow Designer does not contain any connectors (for users with only the regular `user` scope).

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/hB4mjVwD6E1J1dcm3AKZ/Appmixer.png)

We can make all the connectors from the *appmixer* vendor accessible again with the following rule:

![All appmixer components allowed to be used by all users.](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/qIww3PGS9amWoLHWS91P/Appmixer_Backoffice_-_ACL.png)

When you refresh the Appmixer Flow Designer now, you will see all the Appmixer connectors back.

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/SoYNPxB49t5dIiYJoPtC/Appmixer.png)

Let's break down those four properties you can set for each ACL rule.

* **role**: admin | user - those are the default roles/scopes in the system. You can also use an email address or a domain. It means you can define ACL(s) for a single users (email address) or for all users from certain email domain. Let's say your company is called *acme* and your employees all have an email address *<their-name@acme.com>*. Then the domain for ACL rule would be *acme.com*.&#x20;
* **resource**: component type prefix (*appmixer.google.gmail\**  for example). This allows to create rules for components belonging to certain vendor, service or module. In the example above we created a rule for all *appmixer* components. The resource string was *appmixer\** which will cover all *appmixer* components.
* **action**: action the rule is for. In case of components the only action is *use*. You can keep it to \*. There are more actions when it comes to rules for API routes.
* **attributes**: private or non-private. If set to *non-private* the rule will apply to component that do not have `private: true` set in component.json. If set to *private* it will allow users to see private components as well.&#x20;

Let's try more examples. Show only *utils, google* and *slack* components. We're going to add the following three rules:

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/0bovXo3nXvKEgTT3afLF/Appmixer_Backoffice_-_ACL_and_Building_A_Cross_Country_Bike_With_More_Bite___Doddy_s_Perfect_Projects_-_YouTube_%F0%9F%94%8A.png)

When you refresh Appmixer Designer you can see this:

![Only utils, google and slack components available.](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/x4pfwGuK1dCAKC20gVWf/Appmixer.png)

Because we used attribute *non-private* for all our rules we can see only components where `private: true` is not set in their manifest. Most *appmixer* component modules user private auxiliary components for listing items into menus (slack channels for example). Therefore we don't see those private components in this menu:

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/73yXgCVLdF43KpdJyBBq/Appmixer.png)

Let's change the ACL rule for slack module to see those private components as well.

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/sTAJKjeBQCD8qPptvZ10/Appmixer_Backoffice_-_ACL.png)

User can see private components now.

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/XMXcYgfLP8K66ckcq3Ki/Appmixer.png)

When you start writing your own components you should use your own vendor (not *appmixer*). We are adding Hello World component for example under vendor *acme*. Its component type is `acme.custom.component.HelloWorld`. Then we have to publish the component into Appmixer and create new ACL rule that will make it accessible to users.

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/w9BDyEtPy7TdEQ0LTqex/Appmixer_Backoffice_-_ACL.png)

At this point we can find the new *Hello World* component among other components.

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/4AmUVTSGD6qOXeX2vXvW/Appmixer.png)

Another example will show how you can user *resource* property to display only *gmail* modul&#x65;*.*

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/idnURUf56LMiM75FU91Z/Appmixer.png)

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/MyzZWTWs5qEKzpI28zRd/Appmixer_Backoffice_-_ACL.png)

###

### Routes

You can define ACLs to restrict access to [Flows](https://docs.appmixer.com/api/flows) API. The default setting is similar to the one for Components. All roles can access all actions on *flows* resource.&#x20;

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/MBuFYCFFRM9LSIjJOFx1/Appmixer_Backoffice_-_ACL.png)

If you want to limit users from certain role, first you need to delete the general rule. We will show it on *user* role.&#x20;

![](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/voEda6r702l8EJwLBNND/Appmixer_Backoffice_-_ACL.png)

With this setting, any request to any [*/flows*](https://docs.appmixer.com/api/flows) endpoint will result in 403 response code. The following example will show you how to limit access to [*/flows*](https://docs.appmixer.com/api/flows) API for *user* scope to read only operations.

![Read only access to /flows endpoint.](https://content.gitbook.com/content/gA9J5A1N66u2GrNSZK7X/blobs/Hf6h90PAQoGOZqMFWrqR/Appmixer_Backoffice_-_ACL.png)

Those rules are store in mongo DB in the following form:

```
{
    "type" : "routes",
    "acl" : [ 
        {
            "role" : "admin",
            "resource" : "flows",
            "action" : [ 
                "*"
            ],
            "attributes" : [ 
                "*"
            ]
        }, 
        {
            "role" : "tester",
            "resource" : "flows",
            "action" : [ 
                "*"
            ],
            "attributes" : [ 
                "*"
            ]
        }, 
        {
            "role" : "user",
            "resource" : "flows",
            "action" : [ 
                "read"
            ],
            "attributes" : [ 
                "*"
            ]
        }
    ]
}
```

#### Attributes

The next example is not supported in the Backoffice UI, but can be implemented directly using [ACL](https://docs.appmixer.com/api/acl) API. Flows may contain [custom metadata](https://docs.appmixer.com/flows-metadata-and-filtering#setting-custom-metadata). You can use ACL to restrict access to those metadata. We can create a flow with custom metadata like this:

```
{
    "_id" : ObjectId("5f3696f502ea801d405bb112"),
    "userId" : ObjectId("5f3696f102ea801d405bb10e"),
    "flowId" : "c57f1d30-52fc-4a48-97d9-5d1c296064da",
    "stage" : "stopped",
    "name" : "Flow with metadata",
    "btime" : ISODate("2020-08-14T13:51:49.900Z"),
    "mtime" : ISODate("2020-09-01T14:57:43.536Z"),
    "flow" : {
    },
    "mode" : "module",
    "sharedWith" : [],
    "customFields" : {
        "category" : "test-example"
    }
}
```

where `flow.customFields.category = "test-example"`. This can be done through API. But we want only admin users to be able to do so. The following set of ACL rules will allow admins to create custom fields, but it will allow users to only read those fields.&#x20;

```
{
    "type" : "routes",
    "acl" : [ 
        {
            "role" : "admin",
            "resource" : "flows",
            "action" : [ 
                "*"
            ],
            "attributes" : [ 
                "*"
            ]
        }, 
        {
            "role" : "user",
            "resource" : "flows",
            "action" : [ 
                "read"
            ],
            "attributes" : [ 
                "*   // are able to read all attributes, including custom fields
            ]
        }, 
        {
            "role" : "user",
            "resource" : "flows",
            "action" : [ 
                "create"
            ],
            "attributes" : [ 
                "*", "!customFields"   // but they're not able to create them
            ]
        }
    ]
}
```

So if you try to send an API request to create new flow with the following body (as a user with *user* scope).

```
{
    "flow":{},
    "name":"New flow",
    "customFields": {
        "category": "test-category"
    }
}
```

The custom field *category* won't be created. Property *customFields* will be an empty object. Although if you create the same flow with *admin* user that customFields property with category will be created and your user with *user* role will be able to read it (API will return it).

With the following set of rules, users with *user* role won't be able to create and read property *customFields*.

```
{
    "type" : "routes",
    "acl" : [ 
        {
            "role" : "admin",
            "resource" : "flows",
            "action" : [ 
                "*"
            ],
            "attributes" : [ 
                "*"
            ]
        }, 
        {
            "role" : "user",
            "resource" : "flows",
            "action" : [ 
                "read"
            ],
            "attributes" : [ 
                "*", 
                "!customFields"
            ]
        }, 
        {
            "role" : "user",
            "resource" : "flows",
            "action" : [ 
                "create"
            ],
            "attributes" : [ 
                "*", 
                "!customFields"
            ]
        }
    ]
}
```

The same way you restrict access to each property on flows collection.

The next JSON shows different syntax with similar functionality. User with role *user* can read/create flows with properties *flow, name, flowId, stage, sharedWith*, but they won't be able to create *customFields* property.

```
{
    "type" : "routes",
    "acl" : [ 
        {
            "role" : "admin",
            "resource" : "flows",
            "action" : [ 
                "*"
            ],
            "attributes" : [ 
                "*"
            ]
        }, 
        {
            "role" : "user",
            "resource" : "flows",
            "action" : [ 
                "read", 
                "create"
            ],
            "attributes" : [ 
                "flow", 
                "name", 
                "flowId", 
                "stage", 
                "sharedWith"
            ]
        }, 
        {
            "role" : "user",
            "resource" : "flows",
            "action" : [ 
                "!create"
            ],
            "attributes" : [ 
                "customFields"
            ]
        }
    ]
}
```

You can also use nested objects as *attributes.* Let's say the customFields object contains two properties:

```
{
    "_id" : ObjectId("5f4e654c2c2d2f4d59ca89f9"),
    "userId" : ObjectId("5f3696f102ea801d405bb10e"),
    "flowId" : "46d80c28-72c3-42f1-94ba-2c161e26f041",
    "stage" : "stopped",
    "name" : "New flow",
    "btime" : ISODate("2020-09-01T15:14:20.999Z"),
    "mtime" : ISODate("2020-09-01T15:14:20.999Z"),
    "flow" : {},
    "mode" : "module",
    "sharedWith" : [],
    "customFields" : {
        "visible" : "test visible",
        "not-visible" : "test non visible"
    }
}
```

And we want the users to be able to see only *visible* property, the rules would look like this:

```
{
    "type" : "routes",
    "acl" : [ 
        {
            "role" : "admin",
            "resource" : "flows",
            "action" : [ 
                "*"
            ],
            "attributes" : [ 
                "*"
            ]
        }, 
        {
            "role" : "user",
            "resource" : "flows",
            "action" : [ 
                "read"
            ],
            "attributes" : [ 
                "*", 
                "!customFields.not-visible"
            ]
        }, 
        {
            "role" : "user",
            "resource" : "flows",
            "action" : [ 
                "create"
            ],
            "attributes" : [ 
                "*", 
                "!customFields"
            ]
        }
    ]
}
```

Users are not able to create *customFields,* they are allowed to read *customFields.visible* property, but not the *customFields.not-visible.*&#x20;
