<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Error API calling with Service Principal Secret in Data Engineering</title>
    <link>https://community.databricks.com/t5/data-engineering/error-api-calling-with-service-principal-secret/m-p/105360#M42092</link>
    <description>&lt;P&gt;&lt;SPAN&gt;Hi,&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;I am working on Databricks workspace setup on AWS and trying to use Service Principal to execute API calls (CI/CD) deployment through Bitbucket. So I created secret for the service principal and trying to test the token. The test failed with below error:&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;FONT color="#FF0000"&gt;&lt;EM&gt;Using token: doseXXXXXXXXXXXXXXXXXXX calling request get Error 401: {"error_code":401,"message":"Credential was not sent or was of an unsupported type for this API."}&lt;/EM&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;I changed the token to PAT and the script worked fine. Can you please confirm what the issue here. The service principal looks fine as I tested running DLT pipelines successfully via service principal.&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;Here is the script for your reference. This code list the clusters in the workspace:&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;import os
import requests

# Fetch the token from environment variables
databricks_token = 'doseXXXXXXXXXXXXXXXXXXX'

if not databricks_token:
    raise ValueError("DATABRICKS_TOKEN is not set.")

print(f"Using token: {databricks_token}")

# Define the API endpoint and headers
databricks_instance = "https://xxx.databricks.com"  # Replace with your Databricks workspace URL
url = f"{databricks_instance}/api/2.0/clusters/list"
headers = {"Authorization": f"Bearer {databricks_token}"}

# Make the API call
print("calling request get")
response = requests.get(url, headers=headers)

# Check response
if response.status_code == 200:
    print("Success:", response.json())
    # display(response.json())
else:
    print(f"Error {response.status_code}: {response.text}")&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Mon, 13 Jan 2025 09:03:49 GMT</pubDate>
    <dc:creator>DeepankarB</dc:creator>
    <dc:date>2025-01-13T09:03:49Z</dc:date>
    <item>
      <title>Error API calling with Service Principal Secret</title>
      <link>https://community.databricks.com/t5/data-engineering/error-api-calling-with-service-principal-secret/m-p/105360#M42092</link>
      <description>&lt;P&gt;&lt;SPAN&gt;Hi,&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;I am working on Databricks workspace setup on AWS and trying to use Service Principal to execute API calls (CI/CD) deployment through Bitbucket. So I created secret for the service principal and trying to test the token. The test failed with below error:&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;FONT color="#FF0000"&gt;&lt;EM&gt;Using token: doseXXXXXXXXXXXXXXXXXXX calling request get Error 401: {"error_code":401,"message":"Credential was not sent or was of an unsupported type for this API."}&lt;/EM&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;I changed the token to PAT and the script worked fine. Can you please confirm what the issue here. The service principal looks fine as I tested running DLT pipelines successfully via service principal.&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;Here is the script for your reference. This code list the clusters in the workspace:&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;import os
import requests

# Fetch the token from environment variables
databricks_token = 'doseXXXXXXXXXXXXXXXXXXX'

if not databricks_token:
    raise ValueError("DATABRICKS_TOKEN is not set.")

print(f"Using token: {databricks_token}")

# Define the API endpoint and headers
databricks_instance = "https://xxx.databricks.com"  # Replace with your Databricks workspace URL
url = f"{databricks_instance}/api/2.0/clusters/list"
headers = {"Authorization": f"Bearer {databricks_token}"}

# Make the API call
print("calling request get")
response = requests.get(url, headers=headers)

# Check response
if response.status_code == 200:
    print("Success:", response.json())
    # display(response.json())
else:
    print(f"Error {response.status_code}: {response.text}")&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 13 Jan 2025 09:03:49 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/error-api-calling-with-service-principal-secret/m-p/105360#M42092</guid>
      <dc:creator>DeepankarB</dc:creator>
      <dc:date>2025-01-13T09:03:49Z</dc:date>
    </item>
    <item>
      <title>Re: Error API calling with Service Principal Secret</title>
      <link>https://community.databricks.com/t5/data-engineering/error-api-calling-with-service-principal-secret/m-p/105363#M42093</link>
      <description>&lt;P&gt;Hi , Use following oauth token instead. make changes for AWS&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;sample python code:&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;P&gt;import requests&lt;BR /&gt;import json&lt;BR /&gt;import os&lt;/P&gt;&lt;P&gt;# Environment variables (replace with your actual values or use environment variables)&lt;BR /&gt;DATABRICKS_WORKSPACE_URL = os.getenv("DATABRICKS_WORKSPACE_URL")&lt;BR /&gt;CLIENT_ID = os.getenv("CLIENT_ID")&lt;BR /&gt;CLIENT_SECRET = os.getenv("CLIENT_SECRET")&lt;BR /&gt;TENANT_ID = "&amp;lt;&amp;lt;TENANTID&amp;gt;&amp;gt;"&lt;BR /&gt;SCOPE = "2ff814a6-3304-4ab8-85cb-cd0e6f879c1d/.default"&lt;/P&gt;&lt;P&gt;# URLs&lt;BR /&gt;TOKEN_URL = f"&lt;A href="https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token" target="_blank" rel="noopener"&gt;https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token&lt;/A&gt;"&lt;BR /&gt;DATABRICKS_URL = f"{DATABRICKS_WORKSPACE_URL}/api/2.0/token/create"&lt;/P&gt;&lt;P&gt;# Get access token&lt;BR /&gt;payload = {&lt;BR /&gt;"client_id": CLIENT_ID,&lt;BR /&gt;"grant_type": "client_credentials",&lt;BR /&gt;"scope": SCOPE,&lt;BR /&gt;"client_secret": CLIENT_SECRET&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;response = requests.post(TOKEN_URL, data=payload)&lt;BR /&gt;response.raise_for_status() # Raise an error for bad status codes&lt;BR /&gt;access_token_val = response.json()&lt;BR /&gt;access_token = access_token_val.get("access_token")&lt;/P&gt;&lt;P&gt;if not access_token:&lt;BR /&gt;print("Failed to obtain access token")&lt;BR /&gt;exit(1)&lt;/P&gt;&lt;P&gt;print(f"Access Token: {access_token}")&lt;/P&gt;&lt;P&gt;# Create Databricks token&lt;BR /&gt;headers = {&lt;BR /&gt;"Authorization": f"Bearer {access_token}",&lt;BR /&gt;"X-Databricks-Azure-SP-Management-Token": access_token,&lt;BR /&gt;"Content-Type": "application/json"&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;data = {&lt;BR /&gt;"comment": "pipeline token"&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;api_response = requests.post(DATABRICKS_URL, headers=headers, json=data)&lt;BR /&gt;api_response.raise_for_status() # Raise an error for bad status codes&lt;BR /&gt;api_response_json = api_response.json()&lt;BR /&gt;DATABRICKS_NEW_TOKEN = api_response_json.get("token_value")&lt;/P&gt;&lt;P&gt;if not DATABRICKS_NEW_TOKEN:&lt;BR /&gt;print("Token could not be created")&lt;BR /&gt;exit(1)&lt;BR /&gt;else:&lt;BR /&gt;print("Successfully created a Databricks Token")&lt;BR /&gt;print(f"##vso[task.setvariable variable=DATABRICKS_TOKEN;isOutput=true]{DATABRICKS_NEW_TOKEN}")&lt;BR /&gt;print(f"##vso[task.setvariable variable=ACCESS_TOKEN;isOutput=true]{access_token}")&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;</description>
      <pubDate>Mon, 13 Jan 2025 09:56:30 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/error-api-calling-with-service-principal-secret/m-p/105363#M42093</guid>
      <dc:creator>saurabh18cs</dc:creator>
      <dc:date>2025-01-13T09:56:30Z</dc:date>
    </item>
    <item>
      <title>Re: Error API calling with Service Principal Secret</title>
      <link>https://community.databricks.com/t5/data-engineering/error-api-calling-with-service-principal-secret/m-p/105654#M42226</link>
      <description>&lt;P&gt;I have been able to resolve this issue. Apparently you need to generate access token using service principal client id and client secret.&amp;nbsp;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;&lt;DIV class=""&gt;&lt;SPAN class=""&gt;&lt;A class="" href="https://community.databricks.com/t5/user/viewprofilepage/user-id/22314" target="_self"&gt;&lt;SPAN class=""&gt;saurabh18cs&lt;/SPAN&gt;&lt;/A&gt;&amp;nbsp;solution is more relevant to Azure Databricks. Got below link from Databricks which provide generic solution for using service principal:&amp;nbsp;&lt;A title="Manually generate a workspace-level access token" href="https://docs.databricks.com/en/dev-tools/auth/oauth-m2m.html#manually-generate-a-workspace-level-access-token" target="_blank" rel="noopener"&gt;https://docs.databricks.com/en/dev-tools/auth/oauth-m2m.html#manually-generate-a-workspace-level-access-token&lt;/A&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;SPAN class=""&gt;Here is sample code for reference. Ensure that service principal has access to relevant services.&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;import os
import json
import requests
from requests.auth import HTTPBasicAuth


# Set environment variables
os.environ["DATABRICKS_INSTANCE"] = "https://your-databricks-instance"
os.environ["DATABRICKS_TOKEN"] = "your-personal-access-token"
os.environ["DATABRICKS_CLIENT_ID"] = "your-client-id"
os.environ["DATABRICKS_CLIENT_SECRET"] = "your-client-secret"
os.environ["SPFLAG"] = "True"



def get_env_var(var_name):
    """Fetch environment variable with error handling."""
    value = os.getenv(var_name)
    if not value:
        raise ValueError(f"{var_name} is not set.")
    return value


def get_access_token_via_sp(token_endpoint_url, client_id, client_secret):
    """Generate an access token using service principal credentials."""
    data = {
        'grant_type': 'client_credentials',
        'scope': 'all-apis'
    }
    response = requests.post(
        url=token_endpoint_url,
        auth=HTTPBasicAuth(client_id, client_secret),
        data=data
    )

    if response.status_code == 200:
        print("Successfully generated token.")
        return response.json().get("access_token")
    else:
        raise Exception(f"Error {response.status_code}: {response.text}")


def fetch_databricks_clusters(databricks_instance, access_token):
    """Fetch list of Databricks clusters."""
    url = f"{databricks_instance}/api/2.0/clusters/list"
    headers = {"Authorization": f"Bearer {access_token}"}

    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        print("Cluster list fetched successfully.")
        return response.json()
    else:
        raise Exception(f"Error {response.status_code}: {response.text}")


def main():
    # Environment variables
    databricks_instance = get_env_var("DATABRICKS_INSTANCE")
    spflag = os.getenv("SPFLAG", "False").lower() == "true"

    # Access token retrieval
    if spflag:
        token_endpoint_url = f"{databricks_instance}/oidc/v1/token"
        client_id = get_env_var("DATABRICKS_CLIENT_ID")
        client_secret = get_env_var("DATABRICKS_CLIENT_SECRET")
        access_token = get_access_token_via_sp(token_endpoint_url, client_id, client_secret)
    else:
        access_token = get_env_var("DATABRICKS_TOKEN")

    print(f"Using Databricks token: {access_token}")

    # Fetch clusters
    clusters = fetch_databricks_clusters(databricks_instance, access_token)
    print(json.dumps(clusters, indent=2))


if __name__ == "__main__":
    main()&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;</description>
      <pubDate>Tue, 14 Jan 2025 23:59:53 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/error-api-calling-with-service-principal-secret/m-p/105654#M42226</guid>
      <dc:creator>DeepankarB</dc:creator>
      <dc:date>2025-01-14T23:59:53Z</dc:date>
    </item>
  </channel>
</rss>

