Title: Authentication
Source: https://nodely.io/docs/access/authentication/

# Authentication

On a paid plan the edge ties each request to one of your endpoints in one of three ways, checked in this order:

1.  **API token** in a request header: for backends, scripts and bots.
2.  **Whitelisted site**: the request’s `Referer` header is on a domain you verified. For browser apps.
3.  **Whitelisted IP**: the request comes from an address listed on the endpoint. For servers with fixed IPs. Unlimited and Enterprise only: Boost has no IP whitelisting.

A request that matches none of them is anonymous and is not counted under your plan. You manage tokens, sites and IPs per endpoint in the [Nodely portal](https://portal.nodely.io/).

The examples below use the commercial `nodely.io` hosts of Unlimited and Enterprise. On Boost, send the same headers to the public `nodely.dev` hosts instead, for example `https://mainnet-api.4160.nodely.dev`.

<a id="api-tokens"></a>

## API tokens

Each endpoint can have up to 2 tokens on Boost and 3 on Unlimited. Send the token in **one** of these headers. Each of them works on both the node and the indexer hosts.

| Header | Sent by |
| --- | --- |
| `X-Algo-API-Token` | Algod clients of the Algorand SDKs (`algosdk.Algodv2`, py-algorand-sdk `AlgodClient`, …) |
| `X-Indexer-API-Token` | Indexer clients of the SDKs (`algosdk.Indexer`, `IndexerClient`, …) |
| `X-API-Key` | Anything else: curl, plain HTTP clients, reverse proxies |

**curl**

```bash
# Token from the portal, kept in an environment variable
curl -H "X-API-Key: $NODELY_TOKEN" https://mainnet-api.4160.nodely.io/v2/status

curl -H "X-Indexer-API-Token: $NODELY_TOKEN" \
  "https://mainnet-idx.4160.nodely.io/v2/transactions?limit=1"
```

**JavaScript**

```js
// npm install algosdk
import algosdk from "algosdk";

const token = process.env.NODELY_TOKEN;

// The SDK sends a string token as X-Algo-API-Token (algod) or X-Indexer-API-Token (indexer).
const algod = new algosdk.Algodv2(token, "https://mainnet-api.4160.nodely.io", 443);
const indexer = new algosdk.Indexer(token, "https://mainnet-idx.4160.nodely.io", 443);

// Or choose the header yourself.
const algodWithKey = new algosdk.Algodv2({ "X-API-Key": token }, "https://mainnet-api.4160.nodely.io", 443);

console.log(await algod.status().do());
```

**Python**

```python
# pip install py-algorand-sdk
import os
from algosdk.v2client import algod, indexer

token = os.environ["NODELY_TOKEN"]

# Sent as X-Algo-API-Token and X-Indexer-API-Token.
algod_client = algod.AlgodClient(token, "https://mainnet-api.4160.nodely.io")
indexer_client = indexer.IndexerClient(token, "https://mainnet-idx.4160.nodely.io")

print(algod_client.status())
```

Keep tokens out of browsers and git

Anything in a web page, a browser extension or a mobile app bundle can be read by its users. Use a [whitelisted site](https://nodely.io/docs/access/authentication/#browser-apps-whitelisted-sites) for browser apps, and keep tokens in environment variables or a secret store.

To rotate a token, add a new one to the endpoint, deploy it, then delete the old one. A deleted token stops working on the edges within a few minutes.

<a id="browser-apps-whitelisted-sites"></a>

## Browser apps: whitelisted sites

Add your domain to the endpoint in the portal and prove you own it in one of two ways:

-   **DNS**: publish the TXT record the portal shows (`_nodely-verify.<domain>`).
-   **File**: serve the token the portal shows at `https://<domain>/.well-known/nodely-verify.txt`, over HTTPS and without redirects to another host.

Once the site is verified, browser requests whose `Referer` is on that domain, or on any of its subdomains, count under your endpoint. There is no token in your frontend code.

-   Whitelisting `example.com` covers `https://example.com/` and `https://app.example.com/`, over http or https and on any port.
-   You need control of the domain’s DNS or of its web server, so use your own domain. Local development hosts such as `localhost` cannot be verified: develop against the free hosts, or call the API through a small backend that holds a token.
-   Sites are counted per organization, over all its endpoints: Boost 1 (+ extra sites at $2 / month each), public goods 1, Unlimited 5, Enterprise 5. One list feeds both the API (Referer) whitelist and the IPFS gateway. An organization above its cap keeps the sites it verified first whitelisted; nothing is deleted, and the portal warns. A domain can be claimed by one organization only. On Boost, 1 verified site is included and each extra site is $2 / month; every verified site is whitelisted for both the API (Referer) and the IPFS gateway. See \[IPFS gateway\](#ipfs-gateway).

<a id="the-referer-header-must-be-sent"></a>

### The Referer header must be sent

The edge recognises your site only from the `Referer` request header. Browsers send it by default: with the default `strict-origin-when-cross-origin` policy, a call to a Nodely host carries your origin, for example `Referer: https://app.example.com/`. That is all the edge needs.

The header is missing, and the request is anonymous, when:

-   the page sets `Referrer-Policy: no-referrer`, as an HTTP header or as `<meta name="referrer" content="no-referrer">`;
-   the request itself sets `referrerPolicy: "no-referrer"`;
-   a privacy extension strips it.

Keep the default policy, or use `origin` or `strict-origin`. To check, open the browser’s developer tools, select an API call on the Network tab and look for `Referer` under the request headers.

```js
// Works: the default policy sends https://app.example.com/ as the Referer.
await fetch("https://mainnet-api.4160.nodely.io/v2/status");

// Anonymous: no Referer, so the request is not counted under your plan.
await fetch("https://mainnet-api.4160.nodely.io/v2/status", { referrerPolicy: "no-referrer" });
```

Backends should not set a `Referer` header to borrow a site whitelist: use a token or a whitelisted IP.

<a id="servers-with-fixed-ips-whitelisted-ips"></a>

## Servers with fixed IPs: whitelisted IPs

Add the public egress address of your servers, IPv4 or IPv6, to the endpoint. Requests from that address count under your endpoint without any header. Each endpoint can have up to 3 IPs on Unlimited; Boost has no IP whitelisting (use a token or a whitelisted site). An IP address can be whitelisted by one organization only.

IP whitelisting suits servers behind a static IP or a NAT gateway. Serverless functions and other workloads with changing addresses should send a token.

<a id="ipfs-gateway"></a>

## IPFS gateway

The public IPFS gateway at `https://ipfs.algonode.xyz` (backup `https://ipfs.algonode.dev`) serves whitelisted sites only. It also recognises sites from the `Referer` header, so the rules above apply to `<img>` and `fetch` loads alike.

| Plan | Gateway access |
| --- | --- |
| Free | 1 verified site authorized in the portal, within the free daily quota |
| Boost | 1 verified site whitelisted automatically; extra sites $2 / month each. IPFS gateway traffic of Boost sites counts toward the Boost daily quota. |
| Unlimited | Any CID, 5 verified sites per organization whitelisted automatically, within a few minutes |
| Enterprise | Any CID, 5 verified sites per organization whitelisted automatically, within a few minutes |
| Public goods | Any CID, 1 verified site per organization whitelisted automatically, within a few minutes |

On Free, sign up in the [portal](https://portal.nodely.io/) and authorize your site's domain on its IPFS page: it is whitelisted on the gateway only (not on the API), shares the free daily quota of that site, and needs no endpoint or token. For more domains, or a hand-kept whitelist entry, email [support@nodely.io](mailto:support@nodely.io).

Whitelisting is free for Algorand projects. The gateway serves JSON, images, audio and video, up to 100 req/s per IP for Algorand mainnet assets and 10 req/s for other content. Gateway traffic counts toward the free daily quota. More on caching, thumbnails and content rules: [IPFS gateway](https://nodely.io/docs/public/ipfs/).
