> ## Documentation Index
> Fetch the complete documentation index at: https://docs.veadk.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Inbound authentication

Inbound authentication verifies the identity of requests coming into the agent. VeADK supports API keys and OAuth2.

## API key authentication

An API key verifies the caller's identity and authorizes access to API resources with a single string secret. VeADK passes the API key in the URL's `token` parameter.

<Note>
  API keys apply only to the A2A / MCP Server deployment mode; they are not recommended for the VeADK Web mode, which should use OAuth2 instead.
</Note>

Select API-key auth when scaffolding an agent, or add `--auth-method=api-key` when deploying an existing project. The API gateway then validates the API key carried in the `token` URL parameter on each request.

## OAuth2 single sign-on

OAuth2 is an open authorization framework: instead of exposing account credentials, it grants limited access via tokens, so a single login lets users reach multiple related applications without re-authenticating. VeADK offers two integration paths:

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

### API gateway

For VeADK Web apps deployed on VeFaaS, where the API gateway runs the OAuth2 flow.

<Note>
  The API gateway mode requires API gateway version 4.0.0 or later.
</Note>

Select OAuth2 when scaffolding an agent, or add `--auth-method=oauth2` when deploying an existing project; VeADK creates the Identity user pool and client for you. To reuse existing resources, pass `--user-pool-name` and `--client-name` at deploy time.

After deploying, create users in Agent Identity:

<Steps>
  <Step title="Open the user pool">
    In the Volcengine console, go to Agent Identity, select **Authentication › User Pools**, and choose your pool.
  </Step>

  <Step title="Create a user">
    On the pool's **Users** tab, click **New User**, fill in the details, and confirm.
  </Step>
</Steps>

When a user visits the app, the API gateway guides them through login; afterwards you can read the user's JWT from the `Authorization` header.

### Starlette / FastAPI middleware

For local development or self-hosted deployment, VeADK's middleware handles OAuth2 inside the app and supports any Starlette-based framework (including FastAPI). Prefer `OAuth2Config.from_veidentity()`, which auto-configures a VeIdentity user pool:

```python lines theme={null}
from fastapi import FastAPI
from veadk.auth.middleware.oauth2_auth import OAuth2Config, setup_oauth2

app = FastAPI()

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

This creates the user pool and client (if missing), registers the callback URL, and configures the OAuth2 endpoints. Starlette usage is identical — swap `FastAPI()` for `Starlette()`.

To reuse existing resources, disable auto-creation:

```python lines theme={null}
setup_oauth2(
    app,
    OAuth2Config.from_veidentity(
        user_pool_name="existing-pool",
        client_name="existing-client",
        redirect_uri="https://myapp.com/oauth2/callback",
        auto_create=False,             # error if the resource doesn't exist
        auto_register_callback=False,  # don't modify the callback URL
    ),
)
```

Local development needs HTTPS cookies disabled:

```python lines theme={null}
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,  # local HTTP development
    ),
)
```

To use an OAuth2 provider other than VeIdentity, construct `OAuth2Config` directly:

```python lines theme={null}
setup_oauth2(
    app,
    OAuth2Config(
        authorize_url="https://provider.com/oauth2/authorize",
        token_url="https://provider.com/oauth2/token",
        userinfo_url="https://provider.com/oauth2/userinfo",
        client_id="your-client-id",
        client_secret="your-client-secret",
        redirect_uri="https://myapp.com/oauth2/callback",
    ),
)
```

The middleware registers these routes automatically:

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

You can exempt paths from auth: `exempt_paths=["/health", "/metrics"]` (exact match) and `exempt_prefixes=["/public/", "/static/"]` (prefix match). The middleware responds by request type: browser requests redirect to the login page; API requests get a `401`. API requests are detected via the `Accept: application/json` header, a path prefix (default `/api/`), or the `X-Requested-With: XMLHttpRequest` header, and can be customized with `api_path_prefixes`.

Key `OAuth2Config.from_veidentity()` parameters:

| Parameter | Default | Description |
| - | - | - |
| `user_pool_name` | required | VeIdentity user pool name |
| `client_name` | required | User pool client name |
| `redirect_uri` | required | OAuth2 callback URL |
| `auto_create` | `True` | Create resources if missing |
| `auto_register_callback` | `True` | Register the callback URL automatically |
| `client_type` | `WEB_APPLICATION` | Client type |
| `scope` | `"openid profile email"` | OAuth2 scope |

Key `OAuth2Config` parameters:

| Parameter | Default | Description |
| - | - | - |
| `userinfo_url` | `None` | User info endpoint URL; when configured, the middleware fetches user info from this endpoint and stores it in the session |
| `user_id_field` | `"sub"` | Field name used to extract the user identifier from the user info response |
| `session_timeout_seconds` | `3600` | Session timeout (seconds) |
| `cookie_secure` | `True` | Enable secure cookies |
| `auto_refresh_token` | `True` | Refresh tokens automatically |
| `token_refresh_threshold_seconds` | `300` | Token refresh threshold (seconds) |
| `api_path_prefixes` | `["/api/"]` | API path prefixes |

<Note>
  When fetching user info from the userinfo endpoint, only fields safe to store in a browser session cookie are retained: `sub`, `email`, `email_verified`, `name`, `given_name`, `family_name`, `preferred_username`, `picture`, `locale`, `updated_at`, plus the field configured via `user_id_field`. Only values of type string, integer, float, or boolean are kept, to prevent the session cookie from exceeding browser size limits. The `/oauth2/userinfo` endpoint returns these filtered fields.
</Note>

<Note>
  The default `InMemoryStateStore` fits single-process deployments only. For distributed setups, implement a state store backed by Redis or similar and pass it via `setup_oauth2(app, config, state_store=...)`.
</Note>

## OAuth2 JWT authentication

OAuth2 JWT auth combines the OAuth2 framework with JWT, carrying the authorization token as a JWT. It applies to A2A / MCP Server.

Select OAuth2 when scaffolding an agent, or add `--auth-method=oauth2` when deploying; VeADK creates the Identity user pool, or reuses one via `--user-pool-name`. Then create an M2M client in the pool and exchange its credentials for a JWT:

```bash lines theme={null}
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 calls the app, the API gateway validates the JWT they carry; read it from the `Authorization` header.

## Identity propagation in A2A calls

In a call chain that uses the AgentKit A2A registry, VeADK can pass credentials
from the current request to a downstream agent so that it can authorize the call
under the original user identity and trust context.

<Warning>
  Credentials are sent to the resolved downstream A2A endpoint. Call only trusted downstream agents, and give inbound tokens only the permissions required for the task.
</Warning>

| Inbound credential | Downstream behavior |
| - | - |
| `X-Ve-TIP-Token` | Forwarded to the downstream A2A agent in the same header. |
| `Authorization: Bearer <JWT>` | When the downstream AgentCard declares OAuth2, the Bearer JWT is preferred as the downstream `Authorization` header. Other authentication schemes are not propagated as a user JWT. |

For a downstream agent that declares OAuth2, VeADK first sends the propagated
Bearer JWT. It falls back to an OAuth2 M2M token and retries once only when the
downstream endpoint explicitly returns `401 Unauthorized`. Other status codes
and call failures do not trigger M2M fallback, which prevents application or
service failures from being treated as an expired identity token.

### Identity propagation to the skills sandbox

When `execute_skills` calls the skills sandbox, it likewise forwards the
inbound identity credential. VeADK reads the credential stored under the
`inbound_auth` credential key from the credential service and sends it in the
`inbound_auth` request header to the sandbox's A2A endpoint, so the sandbox
workflow runs under the original user identity. If the current request carries
no inbound credential, the header is omitted. See the skill sandbox execution
section in [Code sandboxes](/productions/veadk/preview/en/components/tools/code-sandbox).
