Back to Mlflow

Authentication with Username and Password

docs/docs/self-hosting/security/basic-http-auth.mdx

3.13.042.5 KB
Original Source

import Link from "@docusaurus/Link"; import { APILink } from "@site/src/components/APILink";

Authentication with Username and Password

MLflow supports basic HTTP authentication to enable access control over experiments, registered models, and scorers. Once enabled, any visitor will be required to login before they can view any resource from the Tracking Server.

MLflow Authentication provides Python and REST API for managing users and permissions.

  • <APILink fn="mlflow.server.auth">MLflow Authentication Python API</APILink>
  • <Link to="/api_reference/auth/rest-api.html" target="_blank"><span>MLflow Authentication REST API</span></Link>
  • <Link to="/self-hosting/workspaces/permissions">Workspace Permissions</Link>

Overview

First, install all dependencies required for the basic auth app:

bash
pip install 'mlflow[auth]'

:::note The basic auth app requires a secret key for CSRF protection. Please set the MLFLOW_FLASK_SERVER_SECRET_KEY environment variable before running the mlflow server command. For example:

export MLFLOW_FLASK_SERVER_SECRET_KEY="my-secret-key"

If your setup uses multiple servers, please make sure that this key is consistent between them. Otherwise, you may run into unexpected validation errors. :::

To enable MLflow authentication, launch the MLflow UI with the following command:

bash
mlflow server --app-name basic-auth

Server admin can choose to disable this feature anytime by restarting the server without the app-name flag. Any users and permissions created will be persisted on a SQL database and will be back in service once the feature is re-enabled.

Due to the nature of HTTP authentication, it is only supported on a remote Tracking Server, where users send requests to the server via REST APIs.

How It Works

Permissions

The available permissions are:

<table> <thead> <tr> <th>Permission</th> <th>Can read</th> <th>Can use</th> <th>Can update</th> <th>Can delete</th> <th>Can manage</th> </tr> </thead> <tbody> <tr> <td>READ</td> <td>Yes</td> <td>No</td> <td>No</td> <td>No</td> <td>No</td> </tr> <tr> <td>USE</td> <td>Yes</td> <td>Yes</td> <td>No</td> <td>No</td> <td>No</td> </tr> <tr> <td>EDIT</td> <td>Yes</td> <td>Yes</td> <td>Yes</td> <td>No</td> <td>No</td> </tr> <tr> <td>MANAGE</td> <td>Yes</td> <td>Yes</td> <td>Yes</td> <td>Yes</td> <td>Yes</td> </tr> <tr> <td>NO_PERMISSIONS</td> <td>No</td> <td>No</td> <td>No</td> <td>No</td> <td>No</td> </tr> </tbody> </table>

The default permission for all users is READ. It can be changed in the configuration file.

Permissions are granted via roles. See Role-Based Access Control for the model, scenarios, and API reference. For workspace-wide access controls specifically, see Workspace Permissions. Supported resources include Experiment, Registered Model, Prompt, Scorer, and the AI Gateway resource types (secrets, endpoints, model definitions). Prompt is its own resource type even though prompts share the model-registry wire surface with registered models: a (registered_model, foo, READ) grant does not satisfy a request that targets a prompt with the same name, and vice versa. To access an API endpoint, a user must have the required permission. Otherwise, a 403 Forbidden response will be returned.

Note: RBAC - the role-based model, role API, and admin UI - is available from MLflow 3.13.0. MLflow versions before 3.13 only support the legacy per-resource permission APIs documented below.

:::warning[Pre-RBAC permission management has been removed]

The following surfaces are removed from MLflow 3.13.0 onwards. Calls return 404 or the client method no longer exists. The auth-store backfill migration moves existing grants into the new synthetic-role storage automatically, so existing access survives the upgrade, only the API shape changes.

See Migrating from the legacy permission model for the detailed guidance on how to migrate to the new RBAC permission model.

:::

Required permissions for accessing experiments

<table> <thead> <tr> <th>API</th> <th>Endpoint</th> <th>Method</th> <th>Required permission</th> </tr> </thead> <tbody> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicecreateexperiment" target="_blank"> <span>Create Experiment</span> </Link> </td> <td>`2.0/mlflow/experiments/create`</td> <td>`POST`</td> <td>None</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicegetexperiment" target="_blank"> <span>Get Experiment</span> </Link> </td> <td>`2.0/mlflow/experiments/get`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicegetexperimentbyname" target="_blank"> <span>Get Experiment By Name</span> </Link> </td> <td>`2.0/mlflow/experiments/get-by-name`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicedeleteexperiment" target="_blank"> <span>Delete Experiment</span> </Link> </td> <td>`2.0/mlflow/experiments/delete`</td> <td>`POST`</td> <td>can_delete</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicerestoreexperiment" target="_blank"> <span>Restore Experiment</span> </Link> </td> <td>`2.0/mlflow/experiments/restore`</td> <td>`POST`</td> <td>can_delete</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowserviceupdateexperiment" target="_blank"> <span>Update Experiment</span> </Link> </td> <td>`2.0/mlflow/experiments/update`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicesearchexperiments" target="_blank"> <span>Search Experiments</span> </Link> </td> <td>`2.0/mlflow/experiments/search`</td> <td>`POST`</td> <td>None</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicesearchexperiments" target="_blank"> <span>Search Experiments</span> </Link> </td> <td>`2.0/mlflow/experiments/search`</td> <td>`GET`</td> <td>None</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicesetexperimenttag" target="_blank"> <span>Set Experiment Tag</span> </Link> </td> <td>`2.0/mlflow/experiments/set-experiment-tag`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicecreaterun" target="_blank"> <span>Create Run</span> </Link> </td> <td>`2.0/mlflow/runs/create`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicegetrun" target="_blank"> <span>Get Run</span> </Link> </td> <td>`2.0/mlflow/runs/get`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowserviceupdaterun" target="_blank"> <span>Update Run</span> </Link> </td> <td>`2.0/mlflow/runs/update`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicedeleterun" target="_blank"> <span>Delete Run</span> </Link> </td> <td>`2.0/mlflow/runs/delete`</td> <td>`POST`</td> <td>can_delete</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicerestorerun" target="_blank"> <span>Restore Run</span> </Link> </td> <td>`2.0/mlflow/runs/restore`</td> <td>`POST`</td> <td>can_delete</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicesearchruns" target="_blank"> <span>Search Runs</span> </Link> </td> <td>`2.0/mlflow/runs/search`</td> <td>`POST`</td> <td>None</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicesettag" target="_blank"> <span>Set Tag</span> </Link> </td> <td>`2.0/mlflow/runs/set-tag`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicedeletetag" target="_blank"> <span>Delete Tag</span> </Link> </td> <td>`2.0/mlflow/runs/delete-tag`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicelogmetric" target="_blank"> <span>Log Metric</span> </Link> </td> <td>`2.0/mlflow/runs/log-metric`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicelogparam" target="_blank"> <span>Log Param</span> </Link> </td> <td>`2.0/mlflow/runs/log-parameter`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicelogbatch" target="_blank"> <span>Log Batch</span> </Link> </td> <td>`2.0/mlflow/runs/log-batch`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicelogmodel" target="_blank"> <span>Log Model</span> </Link> </td> <td>`2.0/mlflow/runs/log-model`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicelistartifacts" target="_blank"> <span>List Artifacts</span> </Link> </td> <td>`2.0/mlflow/artifacts/list`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicegetmetrichistory" target="_blank"> <span>Get Metric History</span> </Link> </td> <td>`2.0/mlflow/metrics/get-history`</td> <td>`GET`</td> <td>can_read</td> </tr> </tbody> </table>

Required Permissions for accessing prompt optimization jobs:

:::note Prompt optimization jobs inherit permissions from their parent experiment. When you create a job within an experiment, the job's permissions are determined by your permissions on that experiment. :::

<table> <thead> <tr> <th>API</th> <th>Endpoint</th> <th>Method</th> <th>Required permission</th> </tr> </thead> <tbody> <tr> <td>Create Prompt Optimization Job</td> <td>`3.0/mlflow/prompt-optimization/jobs`</td> <td>`POST`</td> <td>can_update (on experiment)</td> </tr> <tr> <td>Get Prompt Optimization Job</td> <td>`3.0/mlflow/prompt-optimization/jobs/{job_id}`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td>Search Prompt Optimization Jobs</td> <td>`3.0/mlflow/prompt-optimization/jobs/search`</td> <td>`POST`</td> <td>can_read (on experiment)</td> </tr> <tr> <td>Search Prompt Optimization Jobs</td> <td>`3.0/mlflow/prompt-optimization/jobs/search`</td> <td>`GET`</td> <td>can_read (on experiment)</td> </tr> <tr> <td>Cancel Prompt Optimization Job</td> <td>`3.0/mlflow/prompt-optimization/jobs/{job_id}/cancel`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td>Delete Prompt Optimization Job</td> <td>`3.0/mlflow/prompt-optimization/jobs/{job_id}`</td> <td>`DELETE`</td> <td>can_delete</td> </tr> </tbody> </table>

Required Permissions for accessing registered models:

<table> <thead> <tr> <th>API</th> <th>Endpoint</th> <th>Method</th> <th>Required permission</th> </tr> </thead> <tbody> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicecreateregisteredmodel" target="_blank"> <span>Create Registered Model</span> </Link> </td> <td>`2.0/mlflow/registered-models/create`</td> <td>`POST`</td> <td>None</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicerenameregisteredmodel" target="_blank"> <span>Rename Registered Model</span> </Link> </td> <td>`2.0/mlflow/registered-models/rename`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryserviceupdateregisteredmodel" target="_blank"> <span>Update Registered Model</span> </Link> </td> <td>`2.0/mlflow/registered-models/update`</td> <td>`PATCH`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicedeleteregisteredmodel" target="_blank"> <span>Delete Registered Model</span> </Link> </td> <td>`2.0/mlflow/registered-models/delete`</td> <td>`DELETE`</td> <td>can_delete</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicegetregisteredmodel" target="_blank"> <span>Get Registered Model</span> </Link> </td> <td>`2.0/mlflow/registered-models/get`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicesearchregisteredmodels" target="_blank"> <span>Search Registered Models</span> </Link> </td> <td>`2.0/mlflow/registered-models/search`</td> <td>`GET`</td> <td>None</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicegetlatestversions" target="_blank"> <span>Get Latest Versions</span> </Link> </td> <td>`2.0/mlflow/registered-models/get-latest-versions`</td> <td>`POST`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicegetlatestversions" target="_blank"> <span>Get Latest Versions</span> </Link> </td> <td>`2.0/mlflow/registered-models/get-latest-versions`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicesetregisteredmodeltag" target="_blank"> <span>Set Registered Model Tag</span> </Link> </td> <td>`2.0/mlflow/registered-models/set-tag`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicedeleteregisteredmodeltag" target="_blank"> <span>Delete Registered Model Tag</span> </Link> </td> <td>`2.0/mlflow/registered-models/delete-tag`</td> <td>`DELETE`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicesetregisteredmodelalias" target="_blank"> <span>Set Registered Model Alias</span> </Link> </td> <td>`2.0/mlflow/registered-models/alias`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicedeleteregisteredmodelalias" target="_blank"> <span>Delete Registered Model Alias</span> </Link> </td> <td>`2.0/mlflow/registered-models/alias`</td> <td>`DELETE`</td> <td>can_delete</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicegetmodelversionbyalias" target="_blank"> <span>Get Model Version By Alias</span> </Link> </td> <td>`2.0/mlflow/registered-models/alias`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicecreatemodelversion" target="_blank"> <span>Create Model Version</span> </Link> </td> <td>`2.0/mlflow/model-versions/create`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryserviceupdatemodelversion" target="_blank"> <span>Update Model Version</span> </Link> </td> <td>`2.0/mlflow/model-versions/update`</td> <td>`PATCH`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicetransitionmodelversionstage" target="_blank"> <span>Transition Model Version Stage</span> </Link> </td> <td>`2.0/mlflow/model-versions/transition-stage`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicedeletemodelversion" target="_blank"> <span>Delete Model Version</span> </Link> </td> <td>`2.0/mlflow/model-versions/delete`</td> <td>`DELETE`</td> <td>can_delete</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicegetmodelversion" target="_blank"> <span>Get Model Version</span> </Link> </td> <td>`2.0/mlflow/model-versions/get`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicesearchmodelversions" target="_blank"> <span>Search Model Versions</span> </Link> </td> <td>`2.0/mlflow/model-versions/search`</td> <td>`GET`</td> <td>None (results filtered by parent model permission)</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicegetmodelversiondownloaduri" target="_blank"> <span>Get Model Version Download Uri</span> </Link> </td> <td>`2.0/mlflow/model-versions/get-download-uri`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicesetmodelversiontag" target="_blank"> <span>Set Model Version Tag</span> </Link> </td> <td>`2.0/mlflow/model-versions/set-tag`</td> <td>`POST`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicedeletemodelversiontag" target="_blank"> <span>Delete Model Version Tag</span> </Link> </td> <td>`2.0/mlflow/model-versions/delete-tag`</td> <td>`DELETE`</td> <td>can_delete</td> </tr> </tbody> </table>

AI Gateway Permissions

AI Gateway resources (API keys, model definitions, and endpoints) support the same permission model as experiments and registered models. When a user creates a resource, they automatically receive MANAGE permission on it and can grant permissions to other users.

<table> <thead> <tr> <th>API</th> <th>Endpoint</th> <th>Method</th> <th>Required permission</th> </tr> </thead> <tbody> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicelistgatewaysecretinfos" target="_blank"> <span>List API Keys</span> </Link> </td> <td>`3.0/mlflow/gateway/secrets/list`</td> <td>`GET`</td> <td>None</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicegetgatewaysecretinfo" target="_blank"> <span>Get API Key</span> </Link> </td> <td>`3.0/mlflow/gateway/secrets/get`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicecreategatewaysecret" target="_blank"> <span>Create API Key</span> </Link> </td> <td>`3.0/mlflow/gateway/secrets/create`</td> <td>`POST`</td> <td>None</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowserviceupdategatewaysecret" target="_blank"> <span>Update API Key</span> </Link> </td> <td>`3.0/mlflow/gateway/secrets/update`</td> <td>`PATCH`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicedeletegatewaysecret" target="_blank"> <span>Delete API Key</span> </Link> </td> <td>`3.0/mlflow/gateway/secrets/delete`</td> <td>`DELETE`</td> <td>can_delete</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicelistgatewaymodeldefinitions" target="_blank"> <span>List Model Definitions</span> </Link> </td> <td>`3.0/mlflow/gateway/model-definitions/list`</td> <td>`GET`</td> <td>None</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicegetgatewaymodeldefinition" target="_blank"> <span>Get Model Definition</span> </Link> </td> <td>`3.0/mlflow/gateway/model-definitions/get`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicecreategatewaymodeldefinition" target="_blank"> <span>Create Model Definition</span> </Link> </td> <td>`3.0/mlflow/gateway/model-definitions/create`</td> <td>`POST`</td> <td>None (can_use on referenced API key)</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowserviceupdategatewaymodeldefinition" target="_blank"> <span>Update Model Definition</span> </Link> </td> <td>`3.0/mlflow/gateway/model-definitions/update`</td> <td>`PATCH`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicedeletegatewaymodeldefinition" target="_blank"> <span>Delete Model Definition</span> </Link> </td> <td>`3.0/mlflow/gateway/model-definitions/delete`</td> <td>`DELETE`</td> <td>can_delete</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicelistgatewayendpoints" target="_blank"> <span>List Endpoints</span> </Link> </td> <td>`3.0/mlflow/gateway/endpoints/list`</td> <td>`GET`</td> <td>None</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicegetgatewayendpoint" target="_blank"> <span>Get Endpoint</span> </Link> </td> <td>`3.0/mlflow/gateway/endpoints/get`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicecreategatewayendpoint" target="_blank"> <span>Create Endpoint</span> </Link> </td> <td>`3.0/mlflow/gateway/endpoints/create`</td> <td>`POST`</td> <td>None (can_use on referenced model definitions)</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowserviceupdategatewayendpoint" target="_blank"> <span>Update Endpoint</span> </Link> </td> <td>`3.0/mlflow/gateway/endpoints/update`</td> <td>`PATCH`</td> <td>can_update</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicedeletegatewayendpoint" target="_blank"> <span>Delete Endpoint</span> </Link> </td> <td>`3.0/mlflow/gateway/endpoints/delete`</td> <td>`DELETE`</td> <td>can_delete</td> </tr> <tr> <td>Query Endpoint</td> <td>`gateway/{endpoint_name}/...`</td> <td>`POST`</td> <td>can_use</td> </tr> </tbody> </table>

:::note When creating AI Gateway resources, the creator automatically receives MANAGE permission. To grant access to other users, use the permission management APIs listed below. :::

Required Permissions for accessing scorers:

<table> <thead> <tr> <th>API</th> <th>Endpoint</th> <th>Method</th> <th>Required permission</th> </tr> </thead> <tbody> <tr> <td>Register Scorer</td> <td>`3.0/mlflow/scorers/register`</td> <td>`POST`</td> <td>can_update (on experiment)</td> </tr> <tr> <td>List Scorers</td> <td>`3.0/mlflow/scorers/list`</td> <td>`GET`</td> <td>can_read (on experiment)</td> </tr> <tr> <td>Get Scorer</td> <td>`3.0/mlflow/scorers/get`</td> <td>`GET`</td> <td>can_read</td> </tr> <tr> <td>Delete Scorer</td> <td>`3.0/mlflow/scorers/delete`</td> <td>`POST`</td> <td>can_delete</td> </tr> <tr> <td>List Scorer Versions</td> <td>`3.0/mlflow/scorers/list-versions`</td> <td>`GET`</td> <td>can_read</td> </tr> </tbody> </table>

MLflow Authentication provides API endpoints to manage users and permissions.

<table> <thead> <tr> <th>API</th> <th>Endpoint</th> <th>Method</th> <th>Required permission</th> </tr> </thead> <tbody> <tr> <td> <Link to="/api_reference/auth/rest-api.html#create-user" target="_blank"> <span>Create User</span> </Link> </td> <td>`2.0/mlflow/users/create`</td> <td>`POST`</td> <td>None</td> </tr> <tr> <td> <Link to="/api_reference/auth/rest-api.html#get-user" target="_blank"> <span>Get User</span> </Link> </td> <td>`2.0/mlflow/users/get`</td> <td>`GET`</td> <td>Only readable by that user</td> </tr> <tr> <td> <Link to="/api_reference/auth/rest-api.html#update-user-password" target="_blank"> <span>Update User Password</span> </Link> </td> <td>`2.0/mlflow/users/update-password`</td> <td>`PATCH`</td> <td>Only updatable by that user</td> </tr> <tr> <td> <Link to="/api_reference/auth/rest-api.html#update-user-admin" target="_blank"> <span>Update User Admin</span> </Link> </td> <td>`2.0/mlflow/users/update-admin`</td> <td>`PATCH`</td> <td>Only admin</td> </tr> <tr> <td> <Link to="/api_reference/auth/rest-api.html#delete-user" target="_blank"> <span>Delete User</span> </Link> </td> <td>`2.0/mlflow/users/delete`</td> <td>`DELETE`</td> <td>Only admin</td> </tr> <tr> <td> <Link to="/api_reference/auth/rest-api.html#grant-user-permission" target="_blank"> <span>Grant User Permission</span> </Link> </td> <td>`3.0/mlflow/users/permissions/grant`</td> <td>`POST`</td> <td>can_manage on the target resource (or admin)</td> </tr> <tr> <td> <Link to="/api_reference/auth/rest-api.html#revoke-user-permission" target="_blank"> <span>Revoke User Permission</span> </Link> </td> <td>`3.0/mlflow/users/permissions/revoke`</td> <td>`POST`</td> <td>can_manage on the target resource (or admin)</td> </tr> <tr> <td> <Link to="/api_reference/auth/rest-api.html#check-user-permission" target="_blank"> <span>Check User Permission</span> </Link> </td> <td>`3.0/mlflow/auth/check`</td> <td>`POST`</td> <td>self / admin / workspace MANAGE in the resource's workspace</td> </tr> <tr> <td>Create Webhook</td> <td>`2.0/mlflow/webhooks`</td> <td>`POST`</td> <td>Only admin</td> </tr> <tr> <td>List Webhooks</td> <td>`2.0/mlflow/webhooks`</td> <td>`GET`</td> <td>Only admin</td> </tr> <tr> <td>Get Webhook</td> <td>`2.0/mlflow/webhooks/{webhook_id}`</td> <td>`GET`</td> <td>Only admin</td> </tr> <tr> <td>Update Webhook</td> <td>`2.0/mlflow/webhooks/{webhook_id}`</td> <td>`PATCH`</td> <td>Only admin</td> </tr> <tr> <td>Delete Webhook</td> <td>`2.0/mlflow/webhooks/{webhook_id}`</td> <td>`DELETE`</td> <td>Only admin</td> </tr> <tr> <td>Test Webhook</td> <td>`2.0/mlflow/webhooks/{webhook_id}/test`</td> <td>`POST`</td> <td>Only admin</td> </tr> </tbody> </table>

Some APIs will also have their behaviour modified. For example, the creator of an experiment will automatically be granted MANAGE permission on that experiment, so that the creator can grant or revoke other users' access to that experiment.

<table> <thead> <tr> <th>API</th> <th>Endpoint</th> <th>Method</th> <th>Effect</th> </tr> </thead> <tbody> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicecreateexperiment" target="_blank"> <span>Create Experiment</span> </Link> </td> <td>`2.0/mlflow/experiments/create`</td> <td>`POST`</td> <td>Automatically grants `MANAGE` permission to the creator.</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicecreateregisteredmodel" target="_blank"> <span>Create Registered Model</span> </Link> </td> <td>`2.0/mlflow/registered-models/create`</td> <td>`POST`</td> <td>Automatically grants `MANAGE` permission to the creator.</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicesearchexperiments" target="_blank"> <span>Search Experiments</span> </Link> </td> <td>`2.0/mlflow/experiments/search`</td> <td>`POST`</td> <td>Only returns experiments which the user has `READ` permission on.</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicesearchexperiments" target="_blank"> <span>Search Experiments</span> </Link> </td> <td>`2.0/mlflow/experiments/search`</td> <td>`GET`</td> <td>Only returns experiments which the user has `READ` permission on.</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmlflowservicesearchruns" target="_blank"> <span>Search Runs</span> </Link> </td> <td>`2.0/mlflow`</td> <td>`POST`</td> <td>Only returns experiments which the user has `READ` permission on.</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicesearchregisteredmodels" target="_blank"> <span>Search Registered Models</span> </Link> </td> <td>`2.0/mlflow/registered-models/search`</td> <td>`GET`</td> <td>Only returns registered models which the user has `READ` permission on.</td> </tr> <tr> <td> <Link to="/api_reference/rest-api.html#mlflowmodelregistryservicesearchmodelversions" target="_blank"> <span>Search Model Versions</span> </Link> </td> <td>`2.0/mlflow/model-versions/search`</td> <td>`GET`</td> <td>Only returns model versions whose parent registered model the user has `READ` permission on.</td> </tr> </tbody> </table>

Permissions Database

All users and permissions are stored in a database in basic_auth.db, relative to the directory where MLflow server is launched. The location can be changed in the configuration file. To run migrations, use the following command:

bash
python -m mlflow.server.auth db upgrade --url <database_url>

Admin Users

Admin users have unrestricted access to all MLflow resources, including creating or deleting users, updating password and admin status of other users, granting or revoking permissions from other users, and managing permissions for all MLflow resources, even if NO_PERMISSIONS is explicitly set to that admin account.

MLflow has a built-in admin user that will be created the first time that the MLflow authentication feature is enabled.

:::note It is recommended that you update the default admin password as soon as possible after creation. :::

The default admin user credentials are as follows:

<table> <thead> <tr> <th>Username</th> <th>Password</th> </tr> </thead> <tbody> <tr> <td>`admin`</td> <td>`password1234`</td> </tr> </tbody> </table>

Multiple admin users can exist by promoting other users to admin, using the 2.0/mlflow/users/update-admin endpoint.

bash
# authenticate as built-in admin user
export MLFLOW_TRACKING_USERNAME=admin
export MLFLOW_TRACKING_PASSWORD=password
python
from mlflow.server import get_app_client

tracking_uri = "http://localhost:5000/"

auth_client = get_app_client("basic-auth", tracking_uri=tracking_uri)
auth_client.create_user(username="user1", password="pw1")
auth_client.update_user_admin(username="user1", is_admin=True)

Managing Permissions

MLflow provides <Link to="/api_reference/auth/rest-api.html#create-user" target="_blank">REST APIs</Link> and a client class <APILink fn="mlflow.server.auth.client.AuthServiceClient">AuthServiceClient</APILink> for managing users and permissions. To instantiate AuthServiceClient, use <APILink fn="mlflow.server.get_app_client" />.

Permissions are granted via the role API. The three methods you need are:

  • create_role(name, workspace, description=None): create a role
  • add_role_permission(role_id, resource_type, resource_pattern, permission): attach a grant
  • assign_role(username, role_id): assign a user to the role

This is the path for every grant: one user or many, one resource or wildcard, one-off or reusable. For one-user one-resource direct grants use auth_client.grant_user_permission(username, resource_type, resource_id, permission); for shared sets use the role API (create_role + add_role_permission + assign_role). The legacy per-resource methods (create_experiment_permission(), update_registered_model_permission(), etc.) are removed — see the warning above. For one-off grants, the admin UI's Direct permissions section is the simplest path (no role to author). See Role-Based Access Control for the full model, the API reference, and worked scenarios (one-off direct grants, team roles, promoting a user to Workspace Manager, onboarding). For workspace-scoped permissions, see Workspace Permissions.

bash
export MLFLOW_TRACKING_USERNAME=admin
export MLFLOW_TRACKING_PASSWORD=password
python
from mlflow import MlflowClient
from mlflow.server import get_app_client

tracking_uri = "http://localhost:5000/"

auth_client = get_app_client("basic-auth", tracking_uri=tracking_uri)
auth_client.create_user(username="user1", password="pw1")
auth_client.create_user(username="user2", password="pw2")

client = MlflowClient(tracking_uri=tracking_uri)
experiment_id = client.create_experiment(name="experiment")

# Grant user2 MANAGE on this experiment by creating a single-permission role
# and assigning it. The same pattern (``create_role`` -> ``add_role_permission``
# -> ``assign_role``) scales to any number of users and permissions; reuse the
# same role to grant the same access to more users with one ``assign_role``
# call each.
role = auth_client.create_role(name="experiment-manager", workspace="default")
auth_client.add_role_permission(
    role_id=role.id,
    resource_type="experiment",
    resource_pattern=experiment_id,
    permission="MANAGE",
)
auth_client.assign_role(username="user2", role_id=role.id)

Authenticating to MLflow

Using MLflow UI

When a user first visits the MLflow UI on a browser, they will be prompted to login. There is no limit to how many login attempts can be made.

Currently, MLflow UI does not display any information about the current user. Once a user is logged in, the only way to log out is to close the browser.

Using Environment Variables

MLflow provides two environment variables for authentication: MLFLOW_TRACKING_USERNAME and MLFLOW_TRACKING_PASSWORD. To use basic authentication, you must set both environment variables.

bash
export MLFLOW_TRACKING_USERNAME=username
export MLFLOW_TRACKING_PASSWORD=password
python
import mlflow

mlflow.set_tracking_uri("https://<mlflow_tracking_uri>/")
with mlflow.start_run():
    ...

Using Credentials File

You can save your credentials in a file to remove the need for setting environment variables every time. The credentials should be saved in ~/.mlflow/credentials using INI format. Note that the password will be stored unencrypted on disk, and is protected only by filesystem permissions.

If the environment variables MLFLOW_TRACKING_USERNAME and MLFLOW_TRACKING_PASSWORD are configured, they override any credentials provided in the credentials file.

ini
[mlflow]
mlflow_tracking_username = username
mlflow_tracking_password = password

Using REST API

A user can authenticate using the HTTP Authorization request header. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication for more information.

In Python, you can use the requests library:

python
import requests

response = requests.get(
    "https://<mlflow_tracking_uri>/",
    auth=("username", "password"),
)

Creating a New User

:::warning[important] To create a new user, you are required to authenticate with admin privileges. :::

Using MLflow UI

MLflow UI provides a simple page for creating new users at <tracking_uri>/signup.

Using REST API

Alternatively, you can send POST requests to the Tracking Server endpoint 2.0/users/create.

In Python, you can use the requests library:

python
import requests

response = requests.post(
    "https://<mlflow_tracking_uri>/api/2.0/mlflow/users/create",
    json={
        "username": "username",
        "password": "password",
    },
)

Using MLflow AuthServiceClient

MLflow <APILink fn="mlflow.server.auth.client.AuthServiceClient">AuthServiceClient</APILink> provides a function to create new users easily.

python
import mlflow

auth_client = mlflow.server.get_app_client(
    "basic-auth", tracking_uri="https://<mlflow_tracking_uri>/"
)
auth_client.create_user(username="username", password="password")

Configuration

Authentication configuration is located at mlflow/server/auth/basic_auth.ini:

<table> <thead> <tr> <th>Variable</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td>`default_permission`</td> <td>Default permission on all resources</td> </tr> <tr> <td>`grant_default_workspace_access`</td> <td>When workspaces are enabled: if `false`, the `default` workspace ignores `default_permission` and new users need explicit workspace ACLs; if `true`, the `default` workspace inherits `default_permission` for all users (pre-workspaces behavior).</td> </tr> <tr> <td>`database_uri`</td> <td>Database location to store permission and user data</td> </tr> <tr> <td>`admin_username`</td> <td>Default admin username if the admin is not already created</td> </tr> <tr> <td>`admin_password`</td> <td>Default admin password if the admin is not already created</td> </tr> <tr> <td>`authorization_function`</td> <td>Function to authenticate requests</td> </tr> </tbody> </table>

Alternatively, assign the environment variable MLFLOW_AUTH_CONFIG_PATH to point to your custom configuration file.

The authorization_function setting supports pluggable authentication methods if you want to use another authentication method than HTTP basic auth. The value specifies module_name:function_name. The function has the following signature:

python
def authenticate_request() -> Union[Authorization, Response]: ...

The function should return a werkzeug.datastructures.Authorization object if the request is authenticated, or a Response object (typically 401: Unauthorized) if the request is not authenticated. For an example of how to implement a custom authentication method, see tests/server/auth/jwt_auth.py. NOTE: This example is not intended for production use.

Connecting to a Centralized Database

By default, MLflow Authentication uses a local SQLite database to store user and permission data. In the case of a multi-node deployment, it is recommended to use a centralized database to store this data.

To connect to a centralized database, you can set the database_uri configuration variable to the database URL.

ini
[mlflow]
database_uri = postgresql://username:password@hostname:port/database

Then, start the MLflow server with the MLFLOW_AUTH_CONFIG_PATH environment variable set to the path of your configuration file.

bash
MLFLOW_AUTH_CONFIG_PATH=/path/to/my_auth_config.ini mlflow server --app-name basic-auth

The database must be created before starting the MLflow server. The database schema will be created automatically when the server starts.

:::note Auth migrations use a separate version table (alembic_version_auth) from tracking migrations (alembic_version). This allows you to safely use the same database for both tracking data and auth data without migration conflicts.

To use separate databases instead, configure database_uri to point to a different database than --backend-store-uri. By default, auth uses basic_auth.db (SQLite) while tracking uses the database specified by --backend-store-uri. :::