How to connect to Azure sql database with python SQL alchemy using Active directory integrated authentication

Question

I am trying to connect to an Azure SQL Database using SQL Alchemy in python. The database was recently moved to Azure from on-prem and as I understand that azure does not support Windows Auth.
I can connect to the DB from SSMS using Active Directory Integrated Auth.

When the Db was on prem i would use the following connection string and it worked:

"mssql pyodbc://@*Server*/*DB*?driver=SQL Server"

I have tried a few other connection string and cannot get it to work.

"mssql pyodbc://@*Server*/*DB*?driver=SQL Server?Integrated Security=true"
"mssql pyodbc://@*Server*/*DB*?driver=SQL Server?Trusted_Connection=true"

i keep getting the following error, it seems like sql alchemy is trying to connect via windows auth by default is there anyway i can fix this ?

(pyodbc.Error) ('HY000', '[HY000] [Microsoft][ODBC SQL Server Driver][SQL Server]Windows logins are not supported in this version of SQL Server. (40607) (SQLDriverConnect); [HY000] [Microsoft][ODBC SQL Server Driver][SQL Server]Windows logins are not supported in this version of SQL Server. (40607)')
(Background on this error at: http://sqlalche.me/e/dbapi)
Solution

As I known, all of your need are in the offical document Using Azure Active Directory with the ODBC Driver.

First, only the odbc driver 17 version for MS SQL Server supports Active Directory Integrated Authentication if you want to connect to Azure SQL Database by pyodbc. So please make sure you have installed the lastest odbc driver for SQL Server, or you can download from https://docs.microsoft.com/en-us/sql/connect/odbc/microsoft-odbc-driver-for-sql-server?view=sql-server-2017.

Second, please follow the section UI Additions for Azure Active Directory (Windows driver only) to configure the DSN for Azure Active Directory Integrated authentication to SQL Azure.

Then, you can follow the code below to connect to SQL Azure by SQL Alchemy with pyodbc.

from urllib import parse
from sqlalchemy import create_engine

connecting_string = 'Driver={ODBC Driver 17 for SQL Server};Server=tcp:<your sql azure server name>.database.windows.net,1433;Database=<your database name>;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;Authentication=ActiveDirectoryIntegrated'
params = parse.quote_plus(connecting_string)

engine = create_engine("mssql pyodbc:///?odbc_connect=%s" % params)
connection = engine.connect()
result = connection.execute("select 1 1 as res")
for row in result:
    print("res:", row['res'])
connection.close()

Note: The value of connection string above, you can copy it from the `` tab on Azure portal, but please notice to change the odbc driver version and remove the UID and PWD options.

enter image description here

To connect using Windows Integrated or Active Directory Integrated (Windows driver only) authentication, specify Authentication=ActiveDirectoryIntegrated in the connection string. The driver will choose the correct authentication mode automatically. UID and PWD must not be specified.

Or you can consider to use Authentication=ActiveDirectoryPassword which be easier than Authentication=ActiveDirectoryIntegrated and the code as below.

from urllib import parse
from sqlalchemy import create_engine

your_user_name = '<your AAD user or configured in SQL Azure Server as the figure below>'
your_password_here = '<your AAD account password>'
#connecting_string = 'Driver={ODBC Driver 17 for SQL Server};Server=tcp:sqlserverleon.database.windows.net,1433;Database=dbleon;Uid=' your_user_name ';Pwd=' your_password_here ';Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;Authentication=ActiveDirectoryPassword'
connecting_string = 'Driver={ODBC Driver 17 for SQL Server};Server=tcp:sqlserverleon.database.windows.net,1433;Database=dbleon;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;Authentication=ActiveDirectoryIntegrated'
params = parse.quote_plus(connecting_string)

engine = create_engine("mssql pyodbc:///?odbc_connect=%s" % params)
connection = engine.connect()
result = connection.execute("select 1 1 as res")
for row in result:
    print("res:", row['res'])
connection.close()

enter image description here

Hope it helps.