Feature Request: Support for CLI-based authentication

View original issue on GitHub  ·  Variant 3

Adding CLI Authentication Support to the AI Endurance MCP Server

The AI Endurance MCP server currently utilizes a browser-based OAuth 2.0 flow for user authentication. This presents a significant limitation: it prevents the server from being accessed and utilized in non-browser environments, such as command-line interfaces (CLIs), automated scripts, or applications running in headless systems like Docker containers. When a CLI tool attempts to connect, the OAuth 2.0 flow requires a browser redirect, rendering the authentication process impossible to complete.

Root Cause: Browser-Dependent OAuth Flow

The core issue stems from the reliance on the Authorization Code Grant flow with PKCE (Proof Key for Code Exchange), which, while secure for browser-based applications, is inherently interactive. This flow requires a user to be redirected to a login page served by the authorization server (e.g., Google, GitHub), authenticate, and then be redirected back to the application with an authorization code. The application then exchanges this code for an access token. This redirect process is fundamentally incompatible with CLI environments where a browser cannot be opened.

Solution: Implementing Device Authorization Grant

A viable solution is to implement the OAuth 2.0 Device Authorization Grant. This grant type is specifically designed for devices that lack a browser or have limited input capabilities. Here's how it works:

  1. The CLI application makes a request to the authorization server's device authorization endpoint.
  2. The authorization server responds with:
    • A device_code: A short code that the CLI application will use to poll for authorization.
    • A user_code: A longer, more user-friendly code that the user will enter on a separate device (e.g., a smartphone or computer).
    • A verification_uri: The URL where the user will enter the user_code.
    • An expires_in value: The lifetime of the device_code in seconds.
    • An interval value: The minimum interval (in seconds) that the CLI application should use when polling for authorization.
  3. The CLI application displays the user_code and verification_uri to the user.
  4. The user navigates to the verification_uri on a device with a browser and enters the user_code. This authenticates the user.
  5. The CLI application polls the authorization server's token endpoint using the device_code at the specified interval.
  6. Once the user has authenticated, the authorization server returns an access token to the CLI application.

Here's an example of how the CLI application might initiate the device authorization flow:


import requests
import time

# Configuration
CLIENT_ID = "your_client_id"
DEVICE_AUTH_ENDPOINT = "https://your.auth.server/device_authorization"
TOKEN_ENDPOINT = "https://your.auth.server/token"

# 1. Request device and user codes
device_auth_data = {
    "client_id": CLIENT_ID,
    "scope": "your_scopes"
}
response = requests.post(DEVICE_AUTH_ENDPOINT, data=device_auth_data)
response.raise_for_status()  # Raise HTTPError for bad responses (4xx or 5xx)
device_auth_response = response.json()

device_code = device_auth_response["device_code"]
user_code = device_auth_response["user_code"]
verification_uri = device_auth_response["verification_uri"]
expires_in = device_auth_response["expires_in"]
interval = device_auth_response["interval"]

# 2. Display user code and verification URI
print(f"Please visit {verification_uri} and enter the code: {user_code}")

# 3. Poll for the access token
token_data = {
    "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
    "device_code": device_code,
    "client_id": CLIENT_ID
}

start_time = time.time()
while time.time() - start_time < expires_in:
    token_response = requests.post(TOKEN_ENDPOINT, data=token_data)
    token_response_json = token_response.json()

    if token_response.status_code == 200:
        access_token = token_response_json["access_token"]
        print(f"Successfully obtained access token: {access_token}")
        break
    elif token_response_json.get("error") == "authorization_pending":
        print("Authorization pending...")
        time.sleep(interval)
    elif token_response_json.get("error") == "slow_down":
        interval += 5  # Increase the polling interval
        print(f"Slowing down... New interval: {interval} seconds")
        time.sleep(interval)
    else:
        print(f"Error: {token_response_json}")
        break
else:
    print("Device code expired.")

This Python code snippet demonstrates the basic implementation. Remember to replace placeholder values like your_client_id, https://your.auth.server/device_authorization, https://your.auth.server/token, and your_scopes with the actual values for your authorization server.

Practical Tips and Considerations

By implementing the Device Authorization Grant, the AI Endurance MCP server can extend its reach to CLI environments, enabling a wider range of use cases and integrations.