# Secure Upkeeps Using the Forwarder
Source: https://docs.chain.link/chainlink-automation/guides/forwarder

> For the complete documentation index, see [llms.txt](/llms.txt).

This tutorial explains how to use the `Forwarder` to add additional security to your Automation upkeeps. To learn how other Chainlink Automation contracts work, click [here](/chainlink-automation/reference/automation-contracts).

## What is a Forwarder? When is it used?

Each registered upkeep under the Chainlink Automation network has its own unique `Forwarder` contract. The `Forwarder` address becomes available only after upkeep registration, as we deploy a new forwarder for each upkeep. The `Forwarder` contract is the intermediary between the Automation Registry and your Upkeep contract, so you make it the `msg.Sender` for your upkeep.

If you don't use the forwarder address, your contract's `performUpkeep` function is open and callable by anyone. If your contract is without risk of accepting unintentional external data, you don't need to use the forwarder address.

## Securing your upkeep

If your upkeep's perform function needs to be permissioned, please consider setting `msg.sender` as your forwarder address at the top of your `performUpkeep` function.

To make this work you will need to:

- Create `forwarder` as a mutable address variable on your contract that only *you* can update. `forwarder` is a unique value that cannot change for your upkeep.
- Create a `setForwarder` function in your contract so you can update the `forwarder` address.
- Register your upkeep and then retrieve its forwarder address from the Chainlink Automation App or programmatically.
- Call the `setForwarder` function, passing the forwarder address as an input argument.

> **CAUTION: Permissioning for time-based upkeeps**
>
> For [time-based upkeeps](/chainlink-automation/guides/job-scheduler), the **Upkeep address** is the address of the contract that is calling your contract. Do **not** use the forwarder address to permission time-based upkeeps.

In the [Chainlink Automation App](https://automation.chain.link/), open the Details page for your upkeep. Locate the listed **Upkeep address** and use it instead of the **Forwarder address** for permissioning.

### Finding the forwarder address

After you register an upkeep, its forwarder address is available in the Chainlink Automation App. Alternatively, you can fetch it programmatically using `registry.getForwarder(upkeepID)` from the Registry interface.

<TabsContent sharedStore="upkeepType" client:visible>
  <Fragment slot="tab.1">Time-based upkeeps</Fragment>
  <Fragment slot="tab.2">Custom or log trigger upkeeps</Fragment>

  <Fragment slot="panel.1">
    For time-based upkeeps, do **not** use the listed forwarder address. Instead, use the **Upkeep address** shown in the Chainlink Automation App:
    ![Image](/images/automation/cron-upkeep-address.png)

    The **Upkeep address** is shown in the middle card of the **Details** section for your upkeep.
  </Fragment>

  <Fragment slot="panel.2">
    For custom upkeeps or log trigger upkeeps, use the **Forwarder address** listed in the Chainlink Automation App:
    ![Image](/images/automation/forwarder-address-ui.png)

    The **Forwarder address** is shown in the left card of the **Details** section for your upkeep.
  </Fragment>
</TabsContent>

## Code example

The code sample below uses the Forwarder:

```sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @dev Example contract which uses the Forwarder
 *
 * @notice important to implement {AutomationCompatibleInterface}
 */

/**
 * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
 * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
 * DO NOT USE THIS CODE IN PRODUCTION.
 */
import {
  AutomationCompatibleInterface
} from "@chainlink/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol";
import {OwnerIsCreator} from "@chainlink/contracts/src/v0.8/shared/access/OwnerIsCreator.sol";

contract CounterwForwarder is AutomationCompatibleInterface, OwnerIsCreator {
  uint256 public counter; // counter counts the number of upkeeps performed
  uint256 public interval; // interval specifies the time between upkeeps
  uint256 public lastTimeStamp; // lastTimeStamp tracks the last upkeep performed
  address public s_forwarderAddress;

  constructor(
    uint256 updateInterval
  ) {
    interval = updateInterval;
  }

  function checkUpkeep(
    bytes calldata /*checkData*/
  ) external override returns (bool, bytes memory) {
    bool needsUpkeep = (block.timestamp - lastTimeStamp) > interval;
    return (needsUpkeep, bytes(""));
  }

  function performUpkeep(
    bytes calldata /*performData*/
  ) external override {
    require(msg.sender == s_forwarderAddress, "This address does not have permission to call performUpkeep");
    lastTimeStamp = block.timestamp;
    counter = counter + 1;
  }

  /// @notice Set the address that `performUpkeep` is called from
  /// @dev Only callable by the owner
  /// @param forwarderAddress the address to set
  function setForwarderAddress(
    address forwarderAddress
  ) external onlyOwner {
    s_forwarderAddress = forwarderAddress;
  }
}
```