> ## Documentation Index
> Fetch the complete documentation index at: https://proxy-docs.permify.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Contextual Permissions

Contextual tuples are relations that can be dynamically added to permission request operations. When you send these relations along with your requests, they get processed alongside existing relations in the database and will return a result.

You can utilize Contextual Tuples in authorization checks that depend on certain dynamic or contextual data (such as location, time, IP address, etc) that have not been written as traditional Permify relation tuples.

## Use Case

Let's give an example to better understand the usage of Contextual Tuples aka dynamic permissions in access checks.

Consider you're modeling an permission system for an internal application that belongs to an multi regional organization.

### Authorization Model

In that application an employee that belongs to HR department can view details of another employee if:

1. If he/she is an Manager in HR department
2. Connected via the branch's internal network or through the branch's VPN

As you notice we can model rule **1.** easily with our existing schema language, which gives the ability to define arbitrary relations between users and objects such as manager of HR entity, as follows,

```perm theme={null}
entity user {}

entity organization {

    relation employee @user
    relation hr_manager @user @organization#employee

}
```

But to create the `view_employee` permission in the organization entity, we need to consider not only whether the employee is a manager but also check the IP address.

At this point, traditional relation tuples of Permify are insufficient since network address is an dynamic variable that cannot be added as static relations.

So, to incorporate the IP address into our authorization model we will use Contextual Tuples and send dynamic relations values when sending the access check request.

Let's extend our authorization model with adding contextual entities and relations to create the `view_employee` action.

```perm theme={null}
entity user {}

entity organization {

    relation employee @user
    relation hr_manager @user @organization#employee

    relation ip_address_range @ip_address_range

    action view_employee = hr_manager and ip_address_range.user

}

entity ip_address_range {
    relation user @user
}
```

A quick breakdown we define **type** for contextual variable `ip_address_range` and related them with user. Afterwards call that dynamic entities inside our organization entity and form the `view_employee` permission as follows:

```perm theme={null}
action view_employee = hr_manager and ip_address_range.user
```

### Access Check With Contextual Tuples

Since we cannot create relation statically for `ip_address_range` we need to send ip value on runtime, specifically when performing access control check.

So let's say user Ashley trying to view employee X. And lets assume that,

* She has a **manager** relation in HR department with the tuple `organization:1#hr_manager@user:1`
* She connected to VPN which connected to network 192.158.1.38 - which is Branch's internal network.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    data, err := structpb.NewStruct(map[string]interface{}{
    	"ip_address": "192.158.1.38",
    })

    cr, err: = client.Permission.Check(context.Background(), &v1.PermissionCheckRequest {
        TenantId: "t1",
        Metadata: &v1.PermissionCheckRequestMetadata {
            SnapToken: ""
            SchemaVersion: ""
            Depth: 20,
        },
        Entity: &v1.Entity {
            Type: "organization",
            Id: "1",
        },
        Permission: "hr_manager",
        Subject: &v1.Subject {
            Type: "user",
            Id: "1",
        },
        Context: *v1.Context {
            Data: data,
        }

        if (cr.can === PermissionCheckResponse_Result.RESULT_ALLOWED) {
            // RESULT_ALLOWED
        } else {
            // RESULT_DENIED
        }
    })
    ```
  </Tab>

  <Tab title="Node">
    ```javascript theme={null}
    client.permission
      .check({
        tenantId: "t1",
        metadata: {
          snapToken: "",
          schemaVersion: "",
          depth: 20,
        },
        entity: {
          type: "organization",
          id: "1",
        },
        permission: "hr_manager",
        subject: {
          type: "user",
          id: "1",
        },
        context: {
          data: {
            ip_address: "192.158.1.38",
          },
        },
      })
      .then((response) => {
        if (response.can === PermissionCheckResponse_Result.RESULT_ALLOWED) {
          console.log("RESULT_ALLOWED");
        } else {
          console.log("RESULT_DENIED");
        }
      });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import permify
    from permify.models.permission_check_request import PermissionCheckRequest
    from permify.models.permission_check_response import PermissionCheckResponse
    from permify.rest import ApiException
    from pprint import pprint

    configuration = permify.Configuration(host="http://localhost")

    with permify.ApiClient(configuration) as api_client:
        api_instance = permify.PermissionApi(api_client)
        tenant_id = 't1'

        body = PermissionCheckRequest(
            tenant_id=tenant_id,
            metadata={
                "snapToken": "",
                "schemaVersion": "",
                "depth": 20
            },
            entity={
                "type": "organization",
                "id": "1",
            },
            permission="hr_manager",
            subject={
                "type": "user",
                "id": "1",
            },
            context={
                "data": {
                    "ip_address": "192.158.1.38",
                },
            },
        )

        try:
            api_response = api_instance.permissions_check(tenant_id, body)
            if api_response.can == PermissionCheckResponse.Result.RESULT_ALLOWED:
                print("RESULT_ALLOWED")
            else:
                print("RESULT_DENIED")
        except ApiException as e:
            print(f"Exception when calling PermissionApi->permissions_check: {e}")
    ```
  </Tab>

  <Tab title="cURL">
    ```curl theme={null}
    curl --location --request POST 'localhost:3476/v1/tenants/{tenant_id}/permissions/check' \
    --header 'Content-Type: application/json' \
    --data-raw '{
      "metadata":{
        "snap_token": "",
        "schema_version": "",
        "depth": 20
      },
      "entity": {
        "type": "organization",
        "id": "1"
      },
      "permission": "hr_manager",
      "subject": {
        "type": "user",
        "id": "1",
        "relation": ""
      },
      "context": {
        "data": {
            "ip_address": "192.158.1.38",
        }
      }
    }'
    ```
  </Tab>
</Tabs>

## Need any help?

Our team is happy to help you get started with Permify. If you'd like to learn more about using Permify in your app or have any questions about this example, [schedule a consultation call with one of our account executives](https://www.permify.co/book-demo).
