---
title: "Inbound Authentication"
---

Inbound authentication controls who can call your agent—one of the four planes in the [security overview](/en/docs/framework/security). VeADK supports two methods: **API Key** (simple, for A2A/MCP Servers) and **OAuth2** (recommended, with single sign-on). This page covers how to set up each. For the outbound direction (an agent calling external services), see [outbound authentication](/en/docs/framework/security#outbound-authentication).

## API Key authentication

VeADK passes the API Key in the URL `token` query parameter, which the API gateway validates.

<Callout type="info">
API Key only applies to A2A/MCP Server deployments. For VeADK Web deployments, prefer OAuth2.
</Callout>

Choose API Key auth when creating the agent, or add [`--auth-method=api-key`](/en/docs/framework/vefaas) when deploying an existing project. When a user accesses the app, the API gateway validates the API Key in the `token` parameter.

## OAuth2 single sign-on

OAuth2 uses tokens to grant limited access, and one login reaches multiple linked apps. VeADK offers two integration paths:

| Path | When to use | Notes |
| :--- | :--- | :--- |
| API gateway mode | VeFaaS cloud deployment | Deployed via the scaffold; the API gateway handles auth |
| Starlette/FastAPI middleware | Local dev / self-hosted | Integrate the OAuth2 middleware in-app |

### Path 1: API gateway mode (VeFaaS deployment)

The API gateway handles the OAuth2 flow, for VeADK Web apps deployed via VeFaaS.

<Callout type="info">
Requires API gateway version 4.0.0 or later.
</Callout>

Choose OAuth2 auth when creating the agent, or add [`--auth-method=oauth2`](/en/docs/framework/vefaas) when deploying; VeADK automatically creates an Identity user pool and client. To reuse existing resources, pass `--user-pool-name` and `--client-name`.

After deploying, create users under **Identity Auth > User Pool Management** in the Agent Identity console. When a user accesses the app, the API gateway leads them through login, after which you can read the user's JWT from the `Authorization` request header.

### Path 2: Starlette/FastAPI middleware (local / self-hosted)

Use the VeADK middleware to handle OAuth2 in-app. It supports any Starlette-based framework (including FastAPI). The recommended path is `OAuth2Config.from_veidentity()`, which auto-configures a VeIdentity user pool:

```python
from fastapi import FastAPI
from veadk.auth.middleware.oauth2_auth import OAuth2Config, setup_oauth2

app = FastAPI()  # use Starlette() instead for a plain Starlette app

setup_oauth2(
    app,
    OAuth2Config.from_veidentity(
        user_pool_name="my-app",
        client_name="my-app-web",
        redirect_uri="https://myapp.com/oauth2/callback",
    ),
)
```

`from_veidentity()` automatically creates the user pool and client (if absent), registers the callback URL, and configures the OAuth2 endpoints. The middleware registers these routes:

| Route | Purpose |
| :--- | :--- |
| `/oauth2/login` | Start the login flow |
| `/oauth2/callback` | Handle the callback |
| `/oauth2/logout` | Log out and clear the session |
| `/oauth2/userinfo` | Get the current user's info |

The middleware distinguishes request types: browser requests redirect to the login page; API requests get a `401 Unauthorized` JSON response. API requests are detected via `Accept: application/json`, a path prefix (default `/api/`), or `X-Requested-With: XMLHttpRequest`.

#### Common configuration

```python
setup_oauth2(
    app,
    OAuth2Config.from_veidentity(
        user_pool_name="my-app",
        client_name="my-app-web",
        redirect_uri="http://localhost:8000/oauth2/callback",
        cookie_secure=False,           # disable secure cookies for local HTTP dev
        auto_create=False,             # reuse existing resources; error if absent
        auto_register_callback=False,  # don't modify the callback URL
        api_path_prefixes=["/api/", "/graphql"],
    ),
    exempt_paths=["/health", "/metrics"],      # skip auth: exact match
    exempt_prefixes=["/public/", "/static/"],  # skip auth: prefix match
)
```

To integrate a non-VeIdentity OAuth2 provider, construct `OAuth2Config(authorize_url=..., token_url=..., userinfo_url=..., client_id=..., client_secret=..., redirect_uri=...)` directly.

Key `OAuth2Config.from_veidentity()` parameters: `user_pool_name`, `client_name`, `redirect_uri` (required); `auto_create` (default `True`), `auto_register_callback` (default `True`), `client_type` (default `WEB_APPLICATION`), `scope` (default `"openid profile email"`). `OAuth2Config` also supports `session_timeout_seconds` (default `3600`), `cookie_secure` (default `True`), `auto_refresh_token` (default `True`), and `token_refresh_threshold_seconds` (default `300`).

#### Distributed deployment

The default `InMemoryStateStore` only works in a single process. For distributed deployments, use an external store such as Redis—implement the `create_state` / `validate_and_consume_state` methods, for example:

```python
import json
import secrets


class RedisStateStore:
    def __init__(self, redis_client, ttl: int = 300):
        self._redis = redis_client
        self._ttl = ttl

    def create_state(self, redirect_after_auth: str = "/", code_verifier=None) -> str:
        state = secrets.token_urlsafe(32)
        self._redis.setex(
            f"oauth2:{state}",
            self._ttl,
            json.dumps({
                "redirect_after_auth": redirect_after_auth,
                "code_verifier": code_verifier,
            }),
        )
        return state

    def validate_and_consume_state(self, state: str):
        key = f"oauth2:{state}"
        data = self._redis.get(key)
        if not data:
            return None
        self._redis.delete(key)
        return json.loads(data)


setup_oauth2(app, config, state_store=RedisStateStore(redis_client))
```

## OAuth2 JWT authentication

A2A/MCP Servers support carrying the OAuth2 authorization token as a JWT. Choose OAuth2 auth when creating the agent, or add [`--auth-method=oauth2`](/en/docs/framework/vefaas) when deploying; VeADK automatically creates an Identity user pool. To reuse an existing pool, pass `--user-pool-name`.

After deploying, create an M2M-type client under **Identity Auth > User Pool Management** in the Agent Identity console, then generate a JWT with:

```bash
REGION="cn-beijing"
USER_POOL_ID="FILL_IN_YOUR_USER_POOL_ID"
CLIENT_ID="FILL_IN_YOUR_CLIENT_ID"
CLIENT_SECRET="FILL_IN_YOUR_SECRET"

curl --location "https://userpool-${USER_POOL_ID}.userpool.auth.id.${REGION}.volces.com/oauth/token" \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --header "Authorization: Basic $(echo -n "${CLIENT_ID}:${CLIENT_SECRET}" | base64)" \
  --data-urlencode "grant_type=client_credentials"
```

When a user accesses the app, the API gateway validates the JWT; you can read the token from the `Authorization` request header.
