cancel
Showing results for 
Search instead for 
Did you mean: 
Data Engineering
Join discussions on data engineering best practices, architectures, and optimization strategies within the Databricks Community. Exchange insights and solutions with fellow data engineers.
cancel
Showing results for 
Search instead for 
Did you mean: 

OAuth U2M Manual token generation failing

BenDataBricks
New Contributor II

I am writing a frontend webpage that will log into DataBricks and allow the user to select datasets.

I am new to front end development, so there may be some things I am missing here, but I know that the DataBricks SQL connector for javascript only works with Node, which does not work client side. I am aware that there are ways to shoehorn node packages into running in the browser but I am trying to avoid this.

I am looking into using OAuth U2M with manual token generation, as outlined in this article https://learn.microsoft.com/en-us/azure/databricks/dev-tools/auth/oauth-u2m#--manually-generate-and-...
I am able to generate the authorization code in the browser URL just fine (Step 2). However, when I get to the step of generating an OAuth access token (Step3: https://learn.microsoft.com/en-us/azure/databricks/dev-tools/auth/oauth-u2m#--step-3-use-the-authori...), the POST request always returns a 400 with a response of {"error":"invalid_request","error_description":"Invalid authorization code"}

This post request I am doing in python, just as a proof of concept, but I would implement the whole system client side in javascript.

Here is the script I am using for the proof of concept. Any advice on why I keep receiving a 400 would be appreciated. Thanks!

import uuid, hashlib, base64, requests, json, webbrowser
# Generate a UUID.
uuid1 = uuid.uuid4()
# Convert the UUID to a string.
uuid_str1 = str(uuid1).upper()
# Create the code verifier.
code_verifier = uuid_str1 + "-" + uuid_str1
# Create the code challenge based on the code verifier.
code_challenge = base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode()).digest()).decode('utf-8')
# Remove all padding from the code challenge.
code_challenge = code_challenge.replace('=', '')
print(f"code_verifier: {code_verifier}")
print(f"code_challenge: {code_challenge}")
account_id = "**** MY ACCOUNT ID ****"

redirect_url = "http://localhost:8020"
url1 = f"https://accounts.azuredatabricks.net/oidc/accounts/{account_id}/v1/authorize?client_id=databricks-cli&redirect_url={redirect_url}&response_type=code&state=helloworld&code_challenge={code_challenge}&code_challenge_method=S256&scope=all-apis+offline_access"


webbrowser.open(url1, new=2, autoraise=True)
################### Get code from browser

auth_code = "********" # code from browser
body = {"client_id":"databricks-cli","grant_type":"authorization_code","scope":"all-apis offline_access",
"redirect_uri":redirect_url, "code_verifier":code_verifier,"code":auth_code}
url2 = f"https://accounts.azuredatabricks.net/oidc/accounts/{account_id}/v1/token"
r = requests.post(url=url2, data=body)

#This returns
#<Response [400]>
#b'{"error":"invalid_request","error_description":"Invalid authorization code"}'

 

8 REPLIES 8

Kaniz_Fatma
Community Manager
Community Manager

Hi @BenDataBricks

  • Ensure that the auth_code variable in your Python script contains the correct authorization code obtained from the browser.
  • Verify that the code_verifier you’re using matches the one you generated earlier.
  • Confirm that the redirect_url matches the one you’ve set up for your application.
  • Make sure you’re sending the correct parameters in the POST request (client ID, grant type, scope, etc.).

@Kaniz_Fatma I am facing the same issue even though ensured all criteria you mentioned previously.

Hi @MaheshMandlik and @BenDataBricks, If you have already verified that the authorization code, code verifier, code challenge, redirect URI, client ID, and account ID are all correct, and you are still receiving a 400 error with "invalid_request" and "Invalid authorization code" response:-

  1. Use a different browser or clear your browser cache and cookies. 
  2. Double-check the URL you are using for the token endpoint. 
  3. Ensure that the Content-Type header is set correctly in your POST request.
  4. Try using a different HTTP client library in Python to make the POST request, such as urllib or requests-oauthlib, to rule out any issues with the requests library.
  5. Check if there are any proxy settings or firewalls that may be interfering with the request.
  6. Consider using a different OAuth flow, such as the Resource Owner Password Credentials Grant, if it's suitable for your use case. This flow doesn't require an authorization code.
  7. Enable logging or tracing in your Databricks account to see if there are any relevant error messages or logs that can provide more information about the failed request.

Followed this guide thoroughly https://docs.databricks.com/en/dev-tools/auth/oauth-u2m.html#manually-generate-and-use-access-tokens...
Unfortunately, no luck. Surprisingly, it worked well when was used in the month of March 2024.

Slash
New Contributor II

Hi @MaheshMandlik ,

I've got it working. I recommend to split your code into two files, it's a lot easier to test. Once you obtained authorization token, you need to act fast if you want to generate access token, because authorization token are short-lived:

-  get_authorization_token.py
-  get_access_token.py

In get_authorization_token.py:

 

import uuid
import hashlib
import base64
import requests
import json
import webbrowser


# Generate a UUID.
uuid1 = uuid.uuid4()

# Convert the UUID to a string.
uuid_str1 = str(uuid1).upper()

# Create the code verifier.
code_verifier = uuid_str1 + "-" + uuid_str1

# Create the code challenge based on the code verifier.
code_challenge = base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode()).digest()).decode('utf-8')

# Remove all padding from the code challenge.
code_challenge = code_challenge.replace('=', '')

print(f"code_verifier: {code_verifier}")
print(f"code_challenge: {code_challenge}")

account_id = "YOUR_ACCOUNT_ID"
redirect_url = "http://localhost:8020"
url1 = f"https://accounts.azuredatabricks.net/oidc/accounts/{account_id}/v1/authorize?client_id=databricks-cli&redirect_url={redirect_url}&response_type=code&state=helloworld&code_challenge={code_challenge}&code_challenge_method=S256&scope=all-apis+offline_access"  

webbrowser.open(url1, new=2, autoraise=True)

 

 

In get_access_token.py: 

 

import uuid
import hashlib
import base64
import requests
import json
import webbrowser


# Generate a UUID.
uuid1 = uuid.uuid4()

# Convert the UUID to a string.
uuid_str1 = str(uuid1).upper()



account_id = "YOUR_ACCOUNT_ID"
redirect_url = "http://localhost:8020"


authorization_code = "YOUR_AUTHORIZATION_CODE FROM FIRST FILE"

code_verifier = "CODE VERIFIER FROM FIRST FILE"

url = f"https://accounts.azuredatabricks.net/oidc/accounts/{account_id}/v1/token"
data = {
    "client_id": "databricks-cli",
    "grant_type": "authorization_code",
    "scope": "all-apis offline_access",
    "redirect_uri": redirect_url,
    "code_verifier": code_verifier,
    "code": authorization_code
}

response = requests.post(url, data=data)

print(response.status_code)
print(response.json())

 

Slash
New Contributor II

@MaheshMandlik, probably forgot to mention, but splitting this code to two separate files helps to avoid generating new code_verifier by mistake.

MaheshMandlik
Visitor

@Slash Thank you for your help. Your solution has worked very well for me.

Slash
New Contributor II

No problem, glad that I could help. You can also marked my answer as a solution to help community