# CORS in REST channels

Preflights, allowed origins and response headers - serving browser applications from any origin.

Browsers enforce the same-origin policy, so a web application served from one origin can call your REST channels on another origin only if the response includes CORS headers. This page explains what Zato handles automatically and how to serve browser applications from any origin.

## What is built in {#what-is-built-in}

Every REST channel handles CORS automatically for a fixed set of origins:

- `https://zato.io`
- `http://localhost` and `http://127.0.0.1`, on any port

For these origins, a preflight `OPTIONS` request is answered before authentication runs, with status `204 No Content` and these headers:

```text
Access-Control-Allow-Origin: <the origin echoed back>
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: X-API-Key, Authorization, Content-Type
Access-Control-Max-Age: 86400
```

On the actual request that follows, `Access-Control-Allow-Origin` is added to the response. The origin is always echoed back individually, never `*`.

This means local development against a Zato environment requires no setup - a frontend running on `http://localhost:3000` can call your channels without any CORS configuration.

## Serve your own origins {#serve-your-own-origins}

For requests from any other origin, the built-in handling does not add headers and your service sets them itself, through `self.response.headers`:

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class GetCustomer(Service):
    name = 'demo.rest.get-customer'

    def handle(self) -> 'None':

        # The origin your frontend is served from
        allowed_origin = 'https://app.example.com'

        self.response.headers['Access-Control-Allow-Origin'] = allowed_origin
        self.response.payload = {'customer_id': 123, 'name': 'Alexis Martin'}
```

If the browser sends a preflight first - which it does for anything beyond simple GET and POST requests, and always when custom headers such as `X-API-Key` are involved - the `OPTIONS` request reaches the channel like any other request. Handle it with a `handle_OPTIONS` method:

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class GetCustomer(Service):
    name = 'demo.rest.get-customer'

    def _add_cors_headers(self) -> 'None':
        self.response.headers['Access-Control-Allow-Origin'] = 'https://app.example.com'
        self.response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
        self.response.headers['Access-Control-Allow-Headers'] = 'X-API-Key, Content-Type'
        self.response.headers['Access-Control-Max-Age'] = '86400'

    def handle_OPTIONS(self) -> 'None':
        self._add_cors_headers()

    def handle_GET(self) -> 'None':
        self._add_cors_headers()
        self.response.payload = {'customer_id': 123, 'name': 'Alexis Martin'}
```

Preflights sent by browsers never include credentials, so a channel whose service answers its own preflights cannot require security on the `OPTIONS` method. Assign no security definition to such a channel and authenticate the actual requests in the service, or use two channels, one without security for `OPTIONS` and one with security for the remaining methods, both pointing to the same URL path.

## See also {#see-also}

- [REST channels](https://zato.io/docs/dev/rest/channels.html) - Creating the channels that browser applications call
- [HTTP verbs](https://zato.io/docs/dev/rest/verbs.html) - The handle\_OPTIONS and other verb-specific handlers
- [Authentication](https://zato.io/docs/dev/rest/authentication.html) - The security definitions that preflight requests interact with

## Learn more {#learn-more}

- [REST integration overview](https://zato.io/integrations/rest/) - Start here to see how teams build REST integrations
- [In-depth API tutorial](https://zato.io/tutorials/main/01.html) - Master architectural patterns for production-ready integrations
- [Modern REST API tutorial](https://zato.io/tutorials/rest-api/python.html) - Design, build and secure REST APIs with Python
