Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 10 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,9 @@ response = descope_client.magiclink.sign_in_or_up(
login_id="user@example.com"
)

# Extract tokens
# Extract session token
session_token = response["sessionToken"]["jwt"]
refresh_token = response["refreshToken"]["jwt"]

print(f"export DESCOPE_SESSION_TOKEN='{session_token}'")
print(f"export DESCOPE_REFRESH_TOKEN='{refresh_token}'")
```

### 3. Set Environment Variables
Expand All @@ -79,7 +76,6 @@ print(f"export DESCOPE_REFRESH_TOKEN='{refresh_token}'")
# Required
export DESCOPE_PROJECT_ID="P2XXXXX"
export DESCOPE_SESSION_TOKEN="<your-session-token>"
export DESCOPE_REFRESH_TOKEN="<your-refresh-token>"

# Optional (with defaults)
export DESCOPE_ADMIN_ROLES="admin,mlflow-admin"
Expand Down Expand Up @@ -197,15 +193,14 @@ descope = "mlflow_descope_auth.context_provider:DescopeContextProvider"

## Configuration Reference

| Variable | Required | Default | Description |
| ------------------------- | -------- | -------------------- | ----------------------------------------------- |
| `DESCOPE_PROJECT_ID` | ✅ Yes | - | Your Descope Project ID |
| `DESCOPE_SESSION_TOKEN` | ✅ Yes | - | Current session JWT token |
| `DESCOPE_REFRESH_TOKEN` | ❌ No | - | Refresh token for automatic renewal |
| `DESCOPE_ADMIN_ROLES` | ❌ No | `admin,mlflow-admin` | Comma-separated list of admin roles |
| `DESCOPE_DEFAULT_PERMISSION` | ❌ No | `READ` | Default permission level (READ/EDIT/MANAGE) |
| `DESCOPE_USERNAME_CLAIM` | ❌ No | `sub` | JWT claim to use as username (`sub` or `email`) |
| `MLFLOW_TRACKING_AUTH` | ✅ Yes | - | Set to `descope` to enable plugin |
| Variable | Required | Default | Description |
| ---------------------------- | -------- | -------------------- | ----------------------------------------------- |
| `DESCOPE_PROJECT_ID` | ✅ Yes | - | Your Descope Project ID |
| `DESCOPE_SESSION_TOKEN` | ✅ Yes | - | Current session JWT token |
| `DESCOPE_ADMIN_ROLES` | ❌ No | `admin,mlflow-admin` | Comma-separated list of admin roles |
| `DESCOPE_DEFAULT_PERMISSION` | ❌ No | `READ` | Default permission level (READ/EDIT/MANAGE) |
| `DESCOPE_USERNAME_CLAIM` | ❌ No | `sub` | JWT claim to use as username (`sub` or `email`) |
| `MLFLOW_TRACKING_AUTH` | ✅ Yes | - | Set to `descope` to enable plugin |

## Architecture

Expand Down Expand Up @@ -257,10 +252,7 @@ python -c "
from mlflow_descope_auth import get_descope_client
import os
client = get_descope_client()
result = client.validate_session(
os.environ['DESCOPE_SESSION_TOKEN'],
os.environ.get('DESCOPE_REFRESH_TOKEN')
)
result = client.validate_session(os.environ['DESCOPE_SESSION_TOKEN'])
print('✓ Token valid')
"
```
Expand Down
238 changes: 123 additions & 115 deletions docs/QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Get MLflow running with Descope authentication in 5 minutes!

## Prerequisites

- Python 3.8 or higher installed
- Python 3.9 or higher installed
- pip package manager
- A Descope account (free at [descope.com](https://www.descope.com/))

Expand All @@ -15,17 +15,32 @@ Get MLflow running with Descope authentication in 5 minutes!
3. Give it a name (e.g., "MLflow Auth")
4. Copy your **Project ID** (starts with `P2`)

## Step 2: Configure Authentication Flow
## Step 2: Get Authentication Tokens

1. In Descope Console, go to **Authentication → Flows**
2. You'll see a default `sign-up-or-in` flow - click to edit
3. Add your desired authentication methods:
- **OAuth**: Google, GitHub, Microsoft, etc.
- **Magic Link**: Passwordless email authentication
- **OTP**: SMS or email one-time password
- **Password**: Traditional username/password
Authenticate with Descope to obtain session tokens. You can use the Descope Python SDK:

4. Click **Publish** to save your flow
```python
from descope import DescopeClient

descope_client = DescopeClient(project_id="P2XXXXX")

# Authenticate user (example with magic link)
response = descope_client.magiclink.sign_in_or_up(
method="email",
login_id="user@example.com"
)

# Extract session token
session_token = response["sessionToken"]["jwt"]
print(f"export DESCOPE_SESSION_TOKEN='{session_token}'")
```

Or use any other Descope authentication method (OAuth, SAML, etc.) via:
- [Descope Web SDK](https://docs.descope.com/build/guides/client_sdks/web/)
- [Descope Python SDK](https://docs.descope.com/build/guides/client_sdks/python/)
- Descope API directly

> **Note**: Token refresh is handled automatically by the server, not via environment variables.

## Step 3: Install MLflow Descope Auth

Expand All @@ -35,177 +50,170 @@ pip install mlflow-descope-auth

## Step 4: Configure Environment

Create a `.env` file in your project directory:
Set the required environment variables:

```bash
# Required: Your Descope Project ID
DESCOPE_PROJECT_ID=P2XXXXX
# Required
export DESCOPE_PROJECT_ID="P2XXXXX"
export DESCOPE_SESSION_TOKEN="<your-session-token>"

# Optional: Flow ID (default is "sign-up-or-in")
DESCOPE_FLOW_ID=sign-up-or-in
# Enable the plugin
export MLFLOW_TRACKING_AUTH=descope

# Optional: Where to redirect after login (default is "/")
DESCOPE_REDIRECT_URL=/
# Optional (with defaults)
export DESCOPE_ADMIN_ROLES="admin,mlflow-admin"
export DESCOPE_DEFAULT_PERMISSION="READ"
export DESCOPE_USERNAME_CLAIM="sub" # or "email"
```

## Step 5: Run MLflow
## Step 5: Use MLflow

```bash
mlflow server --app-name descope-auth --host 0.0.0.0 --port 5000
```
Once configured, the plugin works automatically with any MLflow client:

```python
import mlflow

## Step 6: Test Authentication
# Set tracking URI to your MLflow server
mlflow.set_tracking_uri("http://localhost:5000")

1. Open your browser and go to `http://localhost:5000`
2. You'll be redirected to the Descope login page
3. Authenticate using one of your configured methods
4. You'll be redirected back to MLflow and logged in!
# Start a run - authentication and user context are automatic!
with mlflow.start_run():
mlflow.log_param("alpha", 0.5)
mlflow.log_metric("rmse", 0.8)
```

The plugin automatically:
- Adds authentication headers to all requests
- Injects user context headers (X-Descope-User-ID, X-Descope-Email, etc.)
- Tags runs with user information (descope.user_id, descope.email, etc.)

## What's Next?

### Verify Plugin is Loaded

```bash
# Check that the plugin is registered
python -c "
from importlib.metadata import entry_points
eps = entry_points(group='mlflow.request_auth_provider')
print([ep.name for ep in eps])
"
# Should include 'descope'
```

### Configure Admin Access

By default, all authenticated users have READ access. To grant admin privileges:

1. In your `.env` file, add:
1. Set admin roles in your environment:

```bash
DESCOPE_ADMIN_ROLES=admin,mlflow-admin
export DESCOPE_ADMIN_ROLES="admin,mlflow-admin"
```

2. In Descope Console, go to **Authorization → Roles**
3. Create a role called `admin` or `mlflow-admin`
4. Assign this role to specific users

### Add More Authentication Methods

1. Go to Descope Console → **Authentication → Flows**
2. Edit your flow and add more methods (OAuth, SAML, etc.)
3. **No code changes needed!** Just publish the flow
4. Restart MLflow to see the changes

### Configure Permissions

Create custom permission mapping in your `.env`:

```bash
# Default permission for all users (READ, EDIT, or MANAGE)
DESCOPE_DEFAULT_PERMISSION=READ
export DESCOPE_DEFAULT_PERMISSION="READ"

# Roles that get admin access (MANAGE permission)
DESCOPE_ADMIN_ROLES=admin,mlflow-admin,superuser
export DESCOPE_ADMIN_ROLES="admin,mlflow-admin,superuser"
```

### Production Deployment
### Automatic Run Tagging

For production, use a proper database:
The plugin automatically adds these tags to all runs:

```bash
mlflow server \
--app-name descope-auth \
--backend-store-uri postgresql://user:pass@localhost/mlflow \
--default-artifact-root s3://my-bucket/mlflow \
--host 0.0.0.0 \
--port 5000
```
- `descope.user_id` - User's Descope ID
- `descope.username` - Username
- `descope.email` - User's email
- `descope.name` - User's display name
- `descope.roles` - Comma-separated list of roles
- `descope.permissions` - Comma-separated list of permissions
- `descope.tenants` - Comma-separated list of tenants

### Docker Deployment

Create `docker-compose.yml`:

```yaml
version: "3.8"

services:
mlflow:
image: python:3.11-slim
command: >
sh -c "
pip install mlflow mlflow-descope-auth &&
mlflow server --app-name descope-auth --host 0.0.0.0
"
environment:
- DESCOPE_PROJECT_ID=${DESCOPE_PROJECT_ID}
- DESCOPE_FLOW_ID=sign-up-or-in
ports:
- "5000:5000"
volumes:
- mlflow-data:/mlflow

volumes:
mlflow-data:
```
### Request Headers

Run with:
The plugin adds these headers to MLflow API requests:

```bash
DESCOPE_PROJECT_ID=P2XXXXX docker-compose up
```
- `X-Descope-User-ID`
- `X-Descope-Username`
- `X-Descope-Email`
- `X-Descope-Roles`
- `X-Descope-Permissions`
- `X-Descope-Tenants`

## Troubleshooting

### Login page shows but authentication fails

**Problem**: Web component loads but authentication doesn't work

**Solution**:

1. Check that your `DESCOPE_PROJECT_ID` is correct
2. Ensure your flow exists in Descope Console
3. Check browser console for errors
4. Verify your domain is whitelisted in Descope Console → **Project Settings → Authentication Hosts**
### Plugin not loaded

### Redirected to login in a loop

**Problem**: After successful authentication, you're redirected back to login
**Problem**: Authentication doesn't work

**Solution**:

1. Clear browser cookies
2. Check that cookies are enabled
3. If using HTTPS, ensure your redirect URL uses HTTPS too
4. Check browser console for cookie errors
```bash
# Verify plugin is installed
pip list | grep mlflow-descope-auth

# Check entry points
python -c "
from importlib.metadata import entry_points
eps = entry_points(group='mlflow.request_auth_provider')
print([ep.name for ep in eps])
"

# Ensure MLFLOW_TRACKING_AUTH is set
echo $MLFLOW_TRACKING_AUTH # Should be "descope"
```

### "DESCOPE_PROJECT_ID is required" error
### Authentication fails

**Problem**: MLflow fails to start
**Problem**: Requests fail with authentication errors

**Solution**:

```bash
# Make sure .env file exists in the same directory
cat .env

# Or set environment variable directly
export DESCOPE_PROJECT_ID=P2XXXXX
mlflow server --app-name descope-auth
# Check environment variables
env | grep DESCOPE

# Verify tokens are valid
python -c "
from mlflow_descope_auth import get_descope_client
import os
client = get_descope_client()
result = client.validate_session(os.environ['DESCOPE_SESSION_TOKEN'])
print('✓ Token valid')
"
```

### Port 5000 already in use
### "DESCOPE_PROJECT_ID is required" error

**Problem**: `Address already in use` error
**Problem**: Plugin fails to initialize

**Solution**:

```bash
# Use a different port
mlflow server --app-name descope-auth --port 5001

# Or kill the process using port 5000
lsof -ti:5000 | xargs kill -9
# Set the required environment variable
export DESCOPE_PROJECT_ID=P2XXXXX
export DESCOPE_SESSION_TOKEN="<your-token>"
```

## Need Help?

- **Documentation**: See [README.md](../README.md) for full documentation
- **Architecture**: See [ARCHITECTURE.md](../ARCHITECTURE.md) for technical details
- **Issues**: [GitHub Issues](https://github.com/descope/mlflow-descope-auth/issues)
- **Descope Docs**: [docs.descope.com](https://docs.descope.com/)

## Next Steps

- Read the [Configuration Guide](../README.md#configuration-reference)
- Learn about [Permission Mapping](../README.md#permission-mapping)
- Explore [Advanced Features](../README.md#advanced-features)
- Check out [Docker Examples](../examples/)
- Read the [Configuration Reference](../README.md#configuration-reference)
- Learn about the [Plugin Architecture](../ARCHITECTURE.md)
- Check out the [Docker Examples](../examples/)

Happy MLflow-ing with Descope! 🚀
Loading