name: 04-authentication
description: >
Use when configuring agent permissions, implementing OBO, or granting access
to Databricks resources. Covers App Authorization (service principal), User
Authorization (OBO), auth passthrough for Model Serving, and MCP server
authentication. Track A Step 4.
license: Apache-2.0
clients: [ide_cli, genie_code]
bundle_resource: none
deploy_verb: none
deploy_note: "Agent permissions / OBO / resource grants — config + grants, no bundle resource. Same model on both clients; on Genie Code run grant CLI steps through runDatabricksCli (pre-authenticated). See skills/genie-code-environment."
coverage: full
metadata:
last_verified: "2026-06-05"
volatility: high
upstream_sources: []
author: "prashanth-subrahmanyam"
version: "3.0.0"
domain: "genai-agents"
pipeline_position: "A4"
consumes: "agent_class"
produces: "authenticated_client, resource_permissions"
grounded_in: "docs.databricks.com/aws/en/generative-ai/agent-framework/agent-authentication, docs.databricks.com/aws/en/generative-ai/agent-framework/agent-authentication-model-serving, docs.databricks.com/aws/en/generative-ai/agent-framework/author-agent"
Agent authentication (Databricks)
Doc-driven skill for how AI agents authenticate on Databricks Apps and Model Serving. Pair with Track A Step 2 (agent_class) when wiring an agent implementation to the right client and grants.
Primary sources:
When to Use
Use this skill whenever you are:
- Configuring permissions for a deployed agent (SP vs user, scopes, resources).
- Implementing user authorization (OBO) in agent handlers.
- Declaring MLflow
resourcesfor automatic authentication passthrough on Model Serving. - Supporting dual deployment (Apps + Model Serving + local) with one codebase.
- Connecting to Databricks MCP servers or external MCP from an agent.
Cross-step impact: The auth patterns you establish here affect both Track A evaluation and deployment (A6/A7) and the SDLC pipeline. Environment detection (local vs Apps vs Model Serving) must work in all three contexts — especially during A6: Evaluation (which runs under your CLI credentials, not OBO) and S6: Deployment & Automation (which provisions a system SP for production).
Two authentication methods overview
| Method | Description | When to use |
|---|---|---|
| App authorization | Agent uses an auto-created service principal with consistent permissions (formerly “SP authentication”). | Most common. All users share the same access; shared indexes, shared experiments, uniform behavior. |
| User authorization | Agent acts as the requesting user (OBO): downscoped token, per-request context. | Per-user permissions, audit trails, Unity Catalog row filters/column masks, fine-grained UC access. |
You can combine both in one agent (for example, app SP for a shared Vector Search index and user client for user-specific tables).
App authorization (default for Databricks Apps)
- Databricks automatically creates a service principal when the app is created; that SP is the app identity.
- All users of the app share the same permissions granted to that SP.
- Grant the SP access via the Databricks Apps UI (Edit app → Configure → resources) or declaratively in
databricks.yml/ bundle app resources. See Apps in bundles.
MLflow experiment
The agent needs an MLflow experiment for traces and evaluation. Grant the SP Can Edit on that experiment and add it as an app resource. See Add an MLflow experiment resource.
Minimum permissions (common resources)
Align grants with official tables; typical minimum expectations for agents:
| Resource | Permission |
|---|---|
| MLflow experiment | Can Edit |
| SQL warehouse | Can Use |
| Model Serving endpoint | Can Query |
| Genie space | Can Run |
| Vector Search index | Can Select |
| Unity Catalog table | SELECT (plus USE SCHEMA / USE CATALOG on parents) |
| Unity Catalog connection | Use Connection |
| Unity Catalog volume | Can Read or Can Read and Write |
| Lakebase | Can Connect and Create |
For the complete permission matrix (all resource types, grant methods, dependency chains), see: references/resource-permissions.md.
Bundle-kind selection: In
databricks.yml, warehouses, serving endpoints, and UC connections have their own top-level kinds (sql_warehouse,serving_endpoint,connection). UC functions/tables/schemas/models use theuc_securablekind with the rightsecurable_type. Another Databricks App (e.g. when an AppKit frontend proxies to an Agent App backend) uses theappkind withCAN_USE. See03-tools-and-mcpfor the full kind-selection table and thedatabricks bundle schemaverification command.
For Model Serving automatic passthrough, permission names and minimum MLflow versions per resource type differ; see the Model Serving authentication page.
Prompt Registry (UC): grant CREATE FUNCTION, EXECUTE, and MANAGE on the UC schema used to store prompts.
Downstream dependencies: If you grant access to a composite resource (for example a Genie space), you must also grant access to dependent objects (underlying tables, warehouses, UC functions, etc.). Missing downstream grants surface as permission denied at runtime.
Who can attach resources: The user adding a resource needs Can Manage on both the resource and the app (per product docs).
Security hardening: follow App authorization for least privilege and credential handling.
For complete app authorization patterns (SP permission granting via UI/CLI/SDK, databricks.yml declarations, least privilege patterns, audit and rotation), see: references/app-authorization.md.
User authorization (OBO) for Databricks Apps
User authorization is Public Preview as of product documentation; workspace admins may need to enable it.
How it works
- Add API scopes in the app so Databricks knows which APIs the app may call on behalf of users. See Add scopes to an app.
- Databricks downscopes the user's credentials to those scopes.
- The downscoped token is forwarded via the
x-forwarded-access-tokenHTTP header. - MLflow Agent Server stores the token per request for use in agent code.
Resources reachable with user authorization (per docs) include SQL warehouses, Genie spaces, files/directories, Model Serving endpoints, Vector Search indexes, UC connections, and UC tables.
Canonical Databricks Apps user headers
Databricks Apps sets the following canonical headers on every inbound request. Read these directly — there is no JSON-blob "user info" header.
x-forwarded-email— the end user's email (canonical attribute used as MLflowAssessmentSource.source_id).x-forwarded-preferred-username— the user's preferred username (often equals the email).x-forwarded-user— the user's stable workspace user id.x-forwarded-access-token— the downscoped OBO token for user-scoped Databricks API calls (only present when the App declaresuser_api_scopes).
x-forwarded-user-info is not a canonical Databricks Apps header and must not be used. Earlier internal patterns assumed it existed; it does not.
Pathway-C: outbound x-app-user-email from AppKit to the Agent App
When the AppKit App (frontend) is a separate Databricks App from the Agent App (backend) — the 2-Apps / Variant 4 / Pathway-C deployment — the AppKit proxy must set x-app-user-email on outbound requests to the Agent App. The agent uses this value as AssessmentSource.source_id for MLflow feedback (see SDLC 04c-end-user-feedback).
Do not infer originating user identity from the app-to-app OAuth token. The Authorization: Bearer header on the inbound agent request represents the AppKit App service principal hop between the two Databricks Apps, not the originating end user. If the agent calls WorkspaceClient().current_user.me() on that Bearer, it gets the AppKit SP — not the user — and every assessment will be attributed to the same SP UUID.
Concretely, in the Agent App's @invoke / @stream handler:
from mlflow.genai import agent_server
import mlflow
@agent_server.invoke
async def handle_invoke(request: dict, http_request) -> dict:
user_email = http_request.headers.get("x-app-user-email") # set by AppKit proxy
# ... run the agent ...
mlflow.log_feedback(
trace_id=trace_id,
name="user_feedback",
value=is_upvoted,
source=mlflow.entities.AssessmentSource(
source_type="HUMAN",
source_id=user_email, # NOT the SP from the Bearer
),
)
The proxy-side wire-up (TypeScript) lives in apps_lakebase/skills/06d-appkit-agent-app-proxy/SKILL.md under "Header Contract".
Declare API scopes in app.yaml (canonical)
Declare the scopes your agent needs in the App's app.yaml under
user_api_scopes. The set should be least privilege — list only the
APIs the agent actually calls on behalf of the user.
# app.yaml — Agent App
command:
- mlflow
- genai
- agent-server
- serve
- --module
- agent
user_api_scopes:
- serving.serving-endpoints # call LLM + KA endpoints as the user
- dashboards.genie # call Genie spaces as the user
- sql.statement-execution # run SQL with user warehouse permissions
- vectorsearch.vector-search-endpoints # if using Vector Search
- catalog.connections # if calling external MCP via UC connection
When a Databricks App declares scopes, the user must consent the first time
they open the app. Token downscoping is enforced by Databricks — your code
just reads x-forwarded-access-token from the incoming request.
Implement in code (Option B canonical)
Import the helper that matches your wrapping pattern:
# Option B (canonical) — module-level @invoke / @stream on Apps:
from databricks_app.utils import get_user_workspace_client
# Option A (legacy) — class-based ResponsesAgent on Model Serving:
# from agent_server.utils import get_user_workspace_client
CRITICAL: Call get_user_workspace_client() inside the request handler (@invoke / @stream for Option B, or predict / predict_stream for Option A), not in __init__ or app startup. There is no user context at startup; initializing early fails or uses the wrong identity.
# Option B canonical — receive the http_request, hand it to the helper
from mlflow.genai import agent_server
from databricks_app.utils import get_user_workspace_client
@agent_server.invoke
async def handle_invoke(request: dict, http_request) -> dict:
ws = get_user_workspace_client(http_request) # user-scoped
response = ws.serving_endpoints.query(
name="my-endpoint",
messages=request["input"],
)
return {"output": response.choices[0].message.content}
For scope design and escalation considerations, see Scope-based security and privilege escalation.
For complete OBO implementation patterns (full agent class, scope walkthrough, token lifecycle, testing locally vs deployed, combining app + user auth), see: references/user-authorization.md.
Automatic auth passthrough (Model Serving)
For agents logged and served on Model Serving, declare dependencies at mlflow.pyfunc.log_model time. Databricks provisions and rotates short-lived credentials (M2M OAuth-style) for a system SP tied to the model version so the agent can call declared resources—no manual PAT wiring for those resources.
Notes from product docs:
- Endpoint creator must be able to access all logged resources.
- The system SP for the model version may not appear in normal SP listings; it is removed if the model version is removed from the endpoint.
- Log all downstream dependencies (same principle as Apps).
Example pattern (trim resources to what your agent actually uses):
from mlflow.models.resources import (
DatabricksServingEndpoint,
DatabricksVectorSearchIndex,
DatabricksLakebase,
)
mlflow.pyfunc.log_model(
python_model="/path/to/agent.py",
resources=[
DatabricksServingEndpoint(endpoint_name="my-llm"),
DatabricksVectorSearchIndex(index_name="prod.docs.index"),
DatabricksLakebase(database_instance_name="my-lakebase"),
],
)
See log agent and mlflow.pyfunc.log_model for full resources types, AuthPolicy / OBO on Model Serving, and MLflow version minimums per resource.
For complete Model Serving auth patterns (all resource types, AuthPolicy, system SP lifecycle, version requirements), see: references/model-serving-auth-passthrough.md.
Environment detection for dual deployment
Use environment signals to pick passthrough resources vs Apps OBO vs local development:
import os
if os.environ.get("IS_IN_DB_MODEL_SERVING_ENV"):
# Model Serving: rely on resources declared at log_model time (and optional OBO policies)
pass
elif os.environ.get("DATABRICKS_APP_NAME"):
# Databricks Apps: user auth via Agent Server helper when using OBO
from agent_server.utils import get_user_workspace_client
client = get_user_workspace_client()
else:
# Local / notebook: default workspace client (user or configured auth)
from databricks.sdk import WorkspaceClient
client = WorkspaceClient()
Treat this as a pattern; exact env vars and client construction should match your template and MLflow/Databricks versions.
For complete OBO authentication patterns (environment detection, error handling, token refresh, production learnings), see: references/obo-authentication.md.
MCP server authentication
Databricks managed MCP
Declare all required resources in
databricks.yml/ bundle and in MLflowresourceswhen applicable.Grant the app's service principal (app authorization) or users (user authorization) access to every downstream UC object the MCP paths touch (for example vector indexes and UC functions under the schemas used in MCP URLs).
Product docs illustrate URL patterns under
/api/2.0/mcp/...; ensure grants cover each index/schema/function namespace your agent uses.Auth header source. When constructing
MCPServerSseinside an@invoke/@streamhandler, pull the bearer token from the user-scoped client to preserve OBO end-to-end:ws = get_user_workspace_client(http_request) ai_search_mcp = MCPServerSse( # AI Search (formerly Vector Search); legacy /mcp/vector-search/ prefix still works url=f"https://{ws.config.host}/api/2.0/mcp/ai-search/prod/docs/idx", headers={"Authorization": f"Bearer {ws.config.token}"}, )Building MCP clients at module load uses the SP token instead — fine for app-authorization, wrong for user-authorization.
For managed MCP, consider databricks_mcp.DatabricksMCPClient().get_databricks_resources() (from the databricks-mcp package) to enumerate dependencies—see Authentication for AI agents (Model Serving).
External MCP servers
- Databricks Apps / agents calling external MCP servers typically use Bearer tokens or OAuth client credentials (M2M) supplied by the external provider, stored and rotated per your platform’s secret management (not PATs for Databricks identity).
- Keep least privilege: scope tokens to the MCP server audience only; do not reuse workspace admin tokens for third-party MCP.
Common mistakes
| Mistake | Impact | Fix |
|---|---|---|
Initializing OBO / get_user_workspace_client() at startup or in __init__ |
No user context; fails or wrong identity | Initialize inside invoke / stream / predict / predict_stream |
| Missing downstream grants (tables behind Genie, functions behind tools, etc.) | Permission denied at runtime | Grant SP or user access to all transitive dependencies |
| Using PATs where product expects OAuth (Apps user auth, passthrough) | Authentication failures or unsupported flows | Use OAuth / forwarded tokens / declared resources per deployment target |
Logging only top-level resource in resources=[...] |
Serving validation or runtime access errors | Log every Databricks resource the code touches |
Validation checklist
- Chosen app authorization, user authorization, or a documented combination for each resource class.
- SP or user has minimum privilege on experiments, warehouses, endpoints, indexes, UC objects, Lakebase, volumes, connections as required.
- Downstream dependencies for Genie, tools, and MCP URLs are granted.
- OBO:
user_api_scopesdeclared inapp.yaml(least privilege) or added via the Apps UI;get_user_workspace_client(http_request)is only called inside@invoke/@streamhandlers. - Model Serving:
resources(andAuthPolicyif using OBO) complete atlog_modeltime. - MCP: bundle/
databricks.ymlresources and UC grants align with every MCP path used. - Dual-env code paths tested in App, serving, and local where applicable.
Next Step
After passing this gate, load and execute
tracks/A-custom-agent-apps/05-lakebase-memory/SKILL.md (A5: Lakebase Memory).
Related Skills
| Skill | Relationship |
|---|---|
| F1: MLflow Foundation | Environment detection patterns from F1 |
| A3: Tools and MCP | Previous step |
| A5: Lakebase Memory | Next step |
| A6: Evaluation | Auth in evaluation context |
| S6: Deployment & Automation | SP permissions for production deployment |
References
- Authentication for AI agents (Databricks Apps)
- Authentication for AI agents (Model Serving)
- Author an AI agent and deploy it on Databricks Apps
- Configure authorization in a Databricks app
- Add resources to a Databricks app
- App authorization (deep dive)
- Apps in bundles
- MLflow Agent Server
- mlflow.pyfunc.log_model