Deploy an agent using on-behalf-of-user authorization
This feature is in Public Preview.
On-behalf-of-user (OBO) authorization lets an agent act as the Databricks user who runs the query. This provides:
- Per-user access to sensitive data
- Fine-grained data controls enforced by Unity Catalog
- Tokens that are restricted (“downscoped”) to only the APIs your agent declares, reducing risk of misuse
Requirements
Databricks recommends installing the latest version of the MLflow Python client when developing agents.
- On-behalf-of-user authorization requires MLflow 2.22.1 and above.
- On-behalf-of-user authorization is disabled by default and must be enabled by a workspace admin. Review the security considerations before enabling this feature.
Supported resources
Agents with OBO authorization can access the following Databricks resources:
Databricks resource | Compatible clients |
---|---|
Vector Search Index |
|
Model Serving Endpoint |
|
SQL Warehouse |
|
UC Connections |
|
UC Tables and Functions | Not directly supported. Use Genie with OBO for structured data access. |
Genie Space |
|
Model Context Protocol (MCP) |
|
Enable on-behalf-of-user authorization
You can continue to use familiar Databricks SDKs and tools (for example, vector search indexes) in your agent code. To enable OBO authorization:
- Update SDK calls to specify that resources are accessed on behalf of the end user.
- Update agent code to initialize OBO access inside the
predict
function, not in__init__
, because the user identity is only known at runtime. - When logging your agent for deployment, declare the Databricks REST API scopes your agent requires. This ensures user tokens are limited to the correct APIs.
For a full walkthrough, see the end-to-end example.
Configure SDKs
The following snippets demonstrate how to configure on-behalf-of-user access to different Databricks resources.
When initializing tools, handle permission errors gracefully. Wrap initialization in a try-except
block to let the agent respond even if the user lacks access. If you don’t handle errors, the agent fails when required resources are missing.
- Vector Search Retriever Tool
- Vector Search Client
- MCP
- Model Serving Endpoint
- UC Connections
- Genie Spaces
from databricks.sdk import WorkspaceClient
from databricks_ai_bridge import ModelServingUserCredentials
from databricks_langchain import VectorSearchRetrieverTool
# Configure a Databricks SDK WorkspaceClient to use on behalf of end
# user authorization
user_client = WorkspaceClient(credentials_strategy = ModelServingUserCredentials())
vector_search_tools = []
# Exclude exception handling if you want the agent to fail
# when users lack access to all required Databricks resources
try:
tool = VectorSearchRetrieverTool(
index_name="<index_name>",
description="...",
tool_name="...",
workspace_client=user_client # Specify the user authorized client
)
vector_search_tools.append(tool)
except Exception as e:
_logger.debug("Skipping adding tool as user does not have permissions")
from databricks.vector_search.client import VectorSearchClient
from databricks.vector_search.utils import CredentialStrategy
# Configure a VectorSearch Client to use on behalf of end
# user authentication
user_authenticated_vsc = VectorSearchClient(credential_strategy=CredentialStrategy.MODEL_SERVING_USER_CREDENTIALS)
# Exclude exception handling if you want the agent to fail when
# users lack access to all required Databricks resources
try:
vs_index = user_authenticated_vsc.get_index(endpoint_name="endpoint_name", index_name="index_name")
...
except Exception as e:
_logger.debug("Skipping Vector Index because user does not have permissions")
from databricks.sdk import WorkspaceClient
from databricks_ai_bridge import ModelServingUserCredentials
from databricks_mcp import DatabricksMCPClient
# Configure a Databricks SDK WorkspaceClient to use on behalf of end
# user authentication
user_client = WorkspaceClient(credentials_strategy=ModelServingUserCredentials())
mcp_client = DatabricksMCPClient(
server_url="<mcp_server_url>",
workspace_client=user_client, # Specify the user client here
)
from databricks.sdk import WorkspaceClient
from databricks_ai_bridge import ModelServingUserCredentials
# Configure a Databricks SDK WorkspaceClient to use on behalf of end
# user authentication
user_client = WorkspaceClient(credentials_strategy=ModelServingUserCredentials())
# Exclude exception handling if you want the agent to fail
# when users lack access to all required Databricks resources
try:
user_client.serving_endpoints.query("endpoint_name", input="")
except Exception as e:
_logger.debug("Skipping Model Serving Endpoint due to no permissions")
from databricks.sdk import WorkspaceClient
from databricks.sdk.service.serving import ExternalFunctionRequestHttpMethod
from databricks_ai_bridge import ModelServingUserCredentials
# Configure a Databricks SDK WorkspaceClient to use on behalf of end
# user authentication
user_client = WorkspaceClient(credentials_strategy=ModelServingUserCredentials())
user_client.serving_endpoints.http_request(
conn="connection_name",
method=ExternalFunctionRequestHttpMethod.POST,
path="/api/v1/resource",
json={"key": "value"},
headers={"extra_header_key": "extra_header_value"},
)
from databricks.sdk import WorkspaceClient
from databricks_ai_bridge import ModelServingUserCredentials
from databricks_langchain.genie import GenieAgent
# Configure a Databricks SDK WorkspaceClient to use on behalf of end
# user authentication
user_client = WorkspaceClient(credentials_strategy=ModelServingUserCredentials())
genie_agent = GenieAgent(
genie_space_id="<genie_space_id>",
genie_agent_name="Genie",
description="Genie_description",
client=user_client, # Specify the user client here
)
Initialize the agent in the predict
function
On-behalf-of-user authorization is compatible with the ResponsesAgent interface.
Because the user's identity is only known at query time, you must access OBO resources inside predict
or predict_stream
, not in the agent's __init__
method. This ensures that resources are isolated between invocations.
from mlflow.pyfunc import ResponsesAgent
class OBOResponsesAgent(ResponsesAgent):
def initialize_agent():
user_client = WorkspaceClient(
credentials_strategy=ModelServingUserCredentials()
)
system_authorized_client = WorkspaceClient()
### Use the clients above to access resources with either system or user authorization
def predict(
self, request
) -> ResponsesAgentResponse:
agent = initialize_agent() # Initialize the Agent in Predict
agent.predict(request)
...
Declare REST API scopes when logging the agent
When you log your OBO agent for deployment, you need to list the Databricks REST API scopes that your agent will call on behalf of the user. This makes sure user tokens are limited to only the APIs your agent actually needs.
This ensures the agent follows the principle of least privilege: tokens are restricted to just the APIs your agent requires, reducing the chance of unauthorized actions or token misuse.
Below is a list of scopes required to access several common types of Databricks resources.
Resource type | Required API scope |
---|---|
Model Serving endpoints |
|
Vector Search endpoints |
|
Vector Search indexes |
|
SQL warehouses |
|
UC connections |
|
MCP Genie spaces |
|
MCP UC functions |
|
MCP Vector Search |
|
MCP external functions |
|
To enable on-behalf-of-user authorization, pass an MLflow AuthPolicy
to log_model()
, as shown in the example below.
An MLflow AuthPolicy
has two components:
system_auth_policy
: Specify resources accessed with system authentication. Use system authentication for shared resources, such as to query model serving endpoints, in combination with on-behalf-of-user authorization for accessing per-user resources or APIs.user_auth_policy
: Specify API scopes your agent needs for on-behalf-of-user authorization. These scopes determine what the agent can do on behalf of the end user.
import mlflow
from mlflow.models.auth_policy import AuthPolicy, SystemAuthPolicy, UserAuthPolicy
from mlflow.models.resources import DatabricksServingEndpoint
# System policy: resources accessed with system credentials
system_policy = SystemAuthPolicy(
resources=[DatabricksServingEndpoint(endpoint_name="my_endpoint")]
)
# User policy: API scopes for OBO access
user_policy = UserAuthPolicy(api_scopes=[
"serving.serving-endpoints",
"vectorsearch.vector-search-endpoints",
"vectorsearch.vector-search-indexes"
])
# Log the agent with both policies
with mlflow.start_run():
mlflow.pyfunc.log_model(
name="agent",
python_model="agent.py",
auth_policy=AuthPolicy(
system_auth_policy=system_policy,
user_auth_policy=user_policy
)
)
Security considerations
Consider the following security considerations before enabling on-behalf-of-user authorization with agents:
-
Expanded resource access: Agents can access sensitive resources on behalf of users. While scopes restrict APIs, endpoints might allow more actions than your agent explicitly requests.
For example, the
serving.serving-endpoints
API scope grants an agent permission to run a serving endpoint on behalf of the user. However, the serving endpoint itself may have access to additional API scopes that the original agent isn't authorized to use.
Example notebook
The following notebook shows you how to create an agent with vector search using on-behalf-of-user authorization.