# Policy Framework

## Introduction

Policies are application entities that authorize a request. A policy is called after a request is validated and sanitized and before the request is executed on the target action. When a policy fails, the default status code is 403. Examples of policies can include

* Verifying the value of the HTTP authorization header
* Checking for violations of rate limits
* Enacting a pay wall

All policies are located in `app/policies`.

## Implementing a Policy

You implement a policy by extending the `Policy` class, and implementing the `runCheck(req)` method. The `runCheck(req)` method must return `true` if the policy passes. If the policy fails, then the `runCheck(req)` method must return `false`, or an the object `{failureCode, failureMessage}`.

{% code title="app/policies/passthrough.js" %}

```javascript
const {Policy} = require ('@onehilltech/blueprint');

module.exports = Policy.extend ({
  runCheck (req) {
    return true;
  }
});
```

{% endcode %}

If the policy check has an asynchronous operation, such as querying a database, then the `runCheck(req)` method can return a `Promise`. The Promise can resolve with `true`, `false`, or the object `{failureCode, failureMessage}`.

## Default Failure Code and Message

The `failureCode` is an application-specific code used to identify the reason for failure. The `failureMessage` is a human readable message that can be displayed to the user. When apply fails, you have the option of returning the object `{failureCode, failureMessage}`. You also have the option of returning `false`. When you return false, there is specification of `failureCode` and `failureMessage`. This is where the default `failureCode` and `failureMessage` for the policy come into play.

{% hint style="info" %}
The default `failureCode` and `failureMessage` is used when the `runCheck(req)` method returns `false`.
{% endhint %}

The default `failureCode` and `failureMessage` are just properties on the `Policy`. Here we have updates the `passthrough` policy from above with a default `failureCode` and `failureMessage`.

{% code title="app/policies/passthrough.js" %}

```javascript
const {Policy} = require ('@onehilltech/blueprint');

module.exports = Policy.extend ({
  failureCode: 'passthrough_failed',
  failureMessage: 'The passthrough policy failed.',
  
  runCheck (req) {
    return true;
  }
});
```

{% endcode %}

Now, when the `runCheck(req)`  method returns false, it will send the following response:

```javascript
{
  errors: [
    {status: '403', code: 'passthrough_failed', detail: 'The passthrough policy failed.'}
  ]
}
```

## Setting Parameters

Policies can also take parameters, which can be used to configure dynamic behavior in a policy. For example, what if we want the passthrough policy to be configured with the result of `true` or `false`. This means we need a way to configure the policy with the expected result. We do this by via policy parameters.

To support parameters, implement the `setParameters()` method on the policy. Each argument in `setParameters()` is an individual parameter. Below, we have updated our simple passthrough policy to use a parameter to define the result of the policy.

{% code title="app/policies/passthrough.js" %}

```javascript
const {Policy} = require ('@onehilltech/blueprint');

module.exports = Policy.extend ({
  failureCode: 'passthrough_failed',
  failureMessage: 'The passthrough policy failed.',
  
  value: true,    // default value is true
  
  setParameters (value) {
    this.value = value;
  },
  
  runCheck (req) {
    return this.value;
  }
});
```

{% endcode %}

As illustrated above, the `setParameters(value)` method stores the parameter value. Likewise, the `runCheck(req)` method uses the parameter value as its result.

## Applying Policies to Routes

Now that we have defined our `passthrough` policy, our next step is to apply the policy to different routes. We apply a policy to a route by naming the policy using the `policy` property in the router specification.&#x20;

{% hint style="info" %}
Use dot notation to access policies located in subdirectories. For example, the policy `a/b/c` can accessed using the name `a.b.c`.
{% endhint %}

In this example, we are applying the passthrough polices to all routes under the `/messages` path.

{% code title="app/routers/message.js" %}

```javascript
const { Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      policy: 'passthrough',
      post: { action: 'message@create' }
    }
  }
});
```

{% endcode %}

Now, anytime we the client sends a request to `/messages` on the application server, the passthrough policy will authorize the request.&#x20;

### Passing Parameters

The default behavior of the [`passthrough`](#setting-parameters) policy is allow the authorization to succeed. This is because the default value of the `value` property is true. But, what if we want the authorization to fail. The [`passthrough`](#setting-parameters) policy supports parameters, but we need to pass `false` to as a parameter value to the policy.

If you need to pass parameters to a policy, then you must use the `check(name, ...args)` method. The first parameter to the `check()` method is the name of the policy. The remaining arguments are the parameters to the policy in-order of their argument specification in `setParameters()`.

We have now updated the example so that the create route will experience a policy failure.

{% code title="app/routers/message.js" %}

```javascript
const { Router, policies: { check } } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      policy: 'passthrough',
      post: { action: 'message@create', policy: check ('passthrough', false) }
    }
  }
});
```

{% endcode %}

## Optional Policies

An optional policy is a policy that is applied if it exists. This is useful when you are defining a router in a Blueprint module, and want to give the module user the option of applying a policy to a route. To declare a policy on a route optional, begin the name with a question mark (`?`). For example, the create action now has an optional policy.

{% code title="app/routers/message.js" %}

```javascript
const { Router, policies: { check } } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      policy: 'passthrough',
      post: { action: 'message@create', policy: check ('?passthrough', false) }
    }
  }
});
```

{% endcode %}

## Negating Policies

Similar to optional policies, you can also negate a policy. For example, if the policy returns true, then the negated policy will return false. If the negated policy returns `false` or `{failureCode, failureMessage}`, then it will return `true`. To negate a policy, begin the policy name with a exclamation point (`!`). For example, the create action now has a negated policy.

{% code title="app/routers/message.js" %}

```javascript
const { Router, policies: { check } } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      policy: 'passthrough',
      post: { action: 'message@create', policy: check ('!passthrough', false) }
    }
  }
});
```

{% endcode %}

## Aggregate Policies

An aggregate policy is a policy created by combining one or more policies. There are two common use cases supported by default. Either all the policies succeed or any of the policies succeed for the aggregate policy to succeed.

### all

Use the `all()` method to create an aggregate policy where all policies must succeed in order for the aggregate policy to succeed. The `all()` method takes a list of policies, and an optional `failureCode` and `failureMessage` parameter.

{% code title="app/routers/message.js" %}

```javascript
const { Router, policies: { check, all } } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      policy: all ([
        'passthrough',
        check ('passthrough', true),
        all (['passthrough', check ('!passthrough', false)])
      ], 'passthroughs_failed', 'All passthrough policies failed')    
      post: { action: 'message@create', policy: check ('!passthrough', false) }
    }
  }
});
```

{% endcode %}

#### Ordered execution

Use `all.ordered()` to evaluate the aggregates policies in order instead of in parallel.

### any

Use the `any()` method to create an aggregate policy where at least one policies must succeed in order for the aggregate policy to succeed. The `any()` method takes a list of policies, and an optional `failureCode` and `failureMessage` parameter.

{% code title="app/routers/message.js" %}

```javascript
const { Router, policies: { check, all } } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      policy: any ([
        'passthrough',
        check ('passthrough', true),
        any (['passthrough', check ('!passthrough', false)])
      ], 'passthroughs_failed', 'All passthrough policies failed')    
      post: { action: 'message@create', policy: check ('!passthrough', false) }
    }
  }
});
```

{% endcode %}

#### Ordered execution

Use `any.ordered()` to evaluate the aggregates policies in order instead of in parallel.
