azure-postgresql-auth 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. azure_postgresql_auth-1.0.0/PKG-INFO +360 -0
  2. azure_postgresql_auth-1.0.0/README.md +311 -0
  3. azure_postgresql_auth-1.0.0/pyproject.toml +104 -0
  4. azure_postgresql_auth-1.0.0/setup.cfg +4 -0
  5. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/__init__.py +20 -0
  6. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/core.py +244 -0
  7. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/errors.py +36 -0
  8. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/psycopg2/__init__.py +25 -0
  9. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/psycopg2/entra_connection.py +78 -0
  10. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/psycopg3/__init__.py +24 -0
  11. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/psycopg3/async_entra_connection.py +66 -0
  12. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/psycopg3/entra_connection.py +66 -0
  13. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/py.typed +0 -0
  14. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/sqlalchemy/__init__.py +28 -0
  15. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/sqlalchemy/async_entra_connection.py +73 -0
  16. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth/sqlalchemy/entra_connection.py +70 -0
  17. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth.egg-info/PKG-INFO +360 -0
  18. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth.egg-info/SOURCES.txt +19 -0
  19. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth.egg-info/dependency_links.txt +1 -0
  20. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth.egg-info/requires.txt +40 -0
  21. azure_postgresql_auth-1.0.0/src/azure_postgresql_auth.egg-info/top_level.txt +1 -0
@@ -0,0 +1,360 @@
1
+ Metadata-Version: 2.4
2
+ Name: azure-postgresql-auth
3
+ Version: 1.0.0
4
+ Summary: Azure Entra ID authentication extension for Python database drivers
5
+ Author-email: Arjun Narendra <v-anarendra@microsoft.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/v-anarendra_microsoft/entra-id-integration-for-drivers
8
+ Project-URL: Issues, https://github.com/v-anarendra_microsoft/entra-id-integration-for-drivers/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: azure-identity>=1.13.0
15
+ Requires-Dist: azure-core>=1.24.0
16
+ Provides-Extra: psycopg3
17
+ Requires-Dist: psycopg[binary]>=3.1.0; extra == "psycopg3"
18
+ Requires-Dist: aiohttp>=3.8.0; extra == "psycopg3"
19
+ Provides-Extra: psycopg2
20
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == "psycopg2"
21
+ Provides-Extra: sqlalchemy
22
+ Requires-Dist: sqlalchemy>=2.0.0; extra == "sqlalchemy"
23
+ Requires-Dist: aiohttp>=3.8.0; extra == "sqlalchemy"
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
26
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
27
+ Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
28
+ Requires-Dist: mypy~=1.15; extra == "dev"
29
+ Requires-Dist: ruff>=0.8.0; extra == "dev"
30
+ Requires-Dist: types-psycopg2>=2.9.0; extra == "dev"
31
+ Requires-Dist: psycopg-pool>=3.1.0; extra == "dev"
32
+ Requires-Dist: testcontainers[postgres]>=3.7.0; extra == "dev"
33
+ Requires-Dist: psycopg[binary]>=3.1.0; extra == "dev"
34
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == "dev"
35
+ Requires-Dist: sqlalchemy>=2.0.0; extra == "dev"
36
+ Provides-Extra: all
37
+ Requires-Dist: psycopg[binary]>=3.1.0; extra == "all"
38
+ Requires-Dist: aiohttp>=3.8.0; extra == "all"
39
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == "all"
40
+ Requires-Dist: sqlalchemy>=2.0.0; extra == "all"
41
+ Requires-Dist: pytest>=7.0.0; extra == "all"
42
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "all"
43
+ Requires-Dist: python-dotenv>=1.0.0; extra == "all"
44
+ Requires-Dist: mypy~=1.15; extra == "all"
45
+ Requires-Dist: ruff>=0.8.0; extra == "all"
46
+ Requires-Dist: types-psycopg2>=2.9.0; extra == "all"
47
+ Requires-Dist: psycopg-pool>=3.1.0; extra == "all"
48
+ Requires-Dist: testcontainers[postgres]>=3.7.0; extra == "all"
49
+
50
+ # azurepg-entra: Azure Database for PostgreSQL Entra ID Authentication
51
+
52
+ This package provides seamless Azure Entra ID authentication for Python database drivers connecting to Azure Database for PostgreSQL. It supports both legacy and modern PostgreSQL drivers with automatic token management and connection pooling.
53
+
54
+ ## Features
55
+
56
+ - **🔐 Azure Entra ID Authentication**: Automatic token acquisition and refresh for secure database connections
57
+ - **🔄 Multi-Driver Support**: Works with psycopg2, psycopg3, and SQLAlchemy
58
+ - **⚡ Connection Pooling**: Built-in support for both synchronous and asynchronous connection pools
59
+ - **🏗️ Clean Architecture**: Simple package structure with `azure_postgresql_auth.psycopg2`, `azure_postgresql_auth.psycopg3`, and `azure_postgresql_auth.sqlalchemy`
60
+ - **🔄 Automatic Token Management**: Handles token acquisition, validation, and refresh automatically
61
+ - **🌐 Cross-platform**: Works on Windows, Linux, and macOS
62
+ - **📦 Flexible Installation**: Optional dependencies for different driver combinations
63
+
64
+ ## Installation
65
+
66
+ ### Basic Installation
67
+
68
+ Install the core package (includes Azure Identity dependencies only):
69
+ ```bash
70
+ pip install azurepg-entra
71
+ ```
72
+
73
+ ### Driver-Specific Installation
74
+
75
+ Choose the installation option based on which PostgreSQL drivers you need:
76
+
77
+ ```bash
78
+ # For psycopg3 (modern psycopg, recommended for new projects)
79
+ pip install "azurepg-entra[psycopg3]"
80
+
81
+ # For psycopg2 (legacy support)
82
+ pip install "azurepg-entra[psycopg2]"
83
+
84
+ # For SQLAlchemy with psycopg3 backend
85
+ pip install "azurepg-entra[sqlalchemy]"
86
+
87
+ # All database drivers combined
88
+ pip install "azurepg-entra[drivers]"
89
+
90
+ # Everything including development tools
91
+ pip install "azurepg-entra[all]"
92
+ ```
93
+
94
+ ### Development Installation
95
+
96
+ Install from source for development:
97
+ ```bash
98
+ git clone https://github.com/v-anarendra_microsoft/entra-id-integration-for-drivers.git
99
+ cd entra-id-integration-for-drivers/python
100
+
101
+ # Install with all dependencies for development
102
+ pip install -e ".[all]"
103
+
104
+ # Or install specific driver combinations
105
+ pip install -e ".[psycopg3,dev]"
106
+ ```
107
+
108
+ ## Configuration
109
+
110
+ ### Environment Variables
111
+
112
+ The samples use environment variables to configure database connections.
113
+
114
+ Copy `.env.example` into a `.env` file in the same directory and update the variables.
115
+ ```env
116
+ POSTGRES_SERVER=<your-server.postgres.database.azure.com>
117
+ POSTGRES_DATABASE=<your_database_name>
118
+ ```
119
+
120
+ ## Quick Start
121
+
122
+ ### Running the Samples
123
+
124
+ The repository includes comprehensive working examples in the `samples/` directory:
125
+
126
+ - **`samples/psycopg2/getting_started/`**: psycopg2 (legacy driver support)
127
+ - **`samples/psycopg3/getting_started/`**: psycopg3 examples (modern driver, recommended)
128
+ - **`samples/sqlalchemy/getting_started/`**: SQLAlchemy examples with psycopg3 backend
129
+
130
+ Configure your environment variables first, then run the samples:
131
+
132
+ ```bash
133
+ # Copy and configure environment
134
+ cp samples/psycopg3/getting_started/.env.example samples/psycopg3/getting_started/.env
135
+ # Edit .env with your Azure PostgreSQL server details
136
+
137
+ # Test psycopg2 (legacy driver)
138
+ python samples/psycopg2/getting_started/create_db_connection_psycopg2.py --mode both
139
+
140
+ # Test psycopg3 (modern driver, recommended)
141
+ python samples/psycopg3/getting_started/create_db_connection_psycopg.py --mode both
142
+
143
+ # Test SQLAlchemy
144
+ python samples/sqlalchemy/getting_started/create_db_connection_sqlalchemy.py --mode both
145
+ ```
146
+
147
+ ## Usage
148
+
149
+ Choose the driver that best fits your project needs:
150
+
151
+ - **psycopg3**: Modern PostgreSQL driver (recommended for new projects)
152
+ - **psycopg2**: Legacy PostgreSQL driver (for existing projects)
153
+ - **SQLAlchemy**: High-level ORM/Core interface
154
+
155
+ ---
156
+
157
+ ## psycopg2 Driver (Legacy Support)
158
+
159
+ > **Note**: psycopg2 is in maintenance mode. For new projects, consider using psycopg3 instead.
160
+
161
+ The psycopg2 integration provides synchronous connection support with Azure Entra ID authentication through connection pooling.
162
+
163
+ ### Installation
164
+ ```bash
165
+ pip install "azurepg-entra[psycopg2]"
166
+ ```
167
+
168
+ ### Connection Pooling (Recommended)
169
+
170
+ ```python
171
+ from azure_postgresql_auth.psycopg2 import EntraConnection # import library
172
+ from psycopg2 import pool # import to use pooling
173
+
174
+ with pool.ThreadedConnectionPool(
175
+ minconn=1,
176
+ maxconn=5,
177
+ host="your-server.postgres.database.azure.com",
178
+ database="your_database",
179
+ connection_factory=EntraConnection
180
+ ) as connection_pool:
181
+ ```
182
+
183
+ ### Direct Connection
184
+
185
+ ```python
186
+ from azure_postgresql_auth.psycopg2 import EntraConnection # import library
187
+
188
+ with EntraConnection(
189
+ "postgresql://your-server.postgres.database.azure.com:5432/your_database"
190
+ ) as conn
191
+ ```
192
+
193
+ ---
194
+
195
+ ## psycopg3 Driver (Recommended)
196
+
197
+ psycopg3 is the modern, actively developed PostgreSQL driver with native async support and better performance.
198
+
199
+ ### Installation
200
+ ```bash
201
+ pip install "azurepg-entra[psycopg3]"
202
+ ```
203
+
204
+ ### Synchronous Connection
205
+
206
+ ```python
207
+ from azure_postgresql_auth.psycopg3 import EntraConnection # import library
208
+ from psycopg_pool import ConnectionPool # import to use pooling
209
+
210
+ with ConnectionPool(
211
+ conninfo="postgresql://your-server.postgres.database.azure.com:5432/your_database",
212
+ connection_class=EntraConnection,
213
+ min_size=1, # keep at least 1 connection always open
214
+ max_size=5, # allow up to 5 concurrent connections
215
+ ) as pool
216
+ ```
217
+
218
+ ### Asynchronous Connection
219
+
220
+ ```python
221
+ from azure_postgresql_auth.psycopg3 import AsyncEntraConnection # import library
222
+ from psycopg_pool import AsyncConnectionPool # import to use pooling
223
+
224
+ async with AsyncConnectionPool(
225
+ conninfo="postgresql://your-server.postgres.database.azure.com:5432/your_database",
226
+ connection_class=AsyncEntraConnection,
227
+ min_size=1, # keep at least 1 connection always open
228
+ max_size=5, # allow up to 5 concurrent connections
229
+ ) as pool
230
+ ```
231
+
232
+ ---
233
+
234
+ ## SQLAlchemy Integration
235
+
236
+ SQLAlchemy integration uses psycopg3 as the backend driver with automatic Entra ID authentication through event listeners.
237
+
238
+ > **For more information**: See SQLAlchemy's documentation on [controlling how parameters are passed to the DBAPI connect function](https://docs.sqlalchemy.org/en/20/core/engines.html#controlling-how-parameters-are-passed-to-the-dbapi-connect-function).
239
+
240
+ ### Installation
241
+ ```bash
242
+ pip install "azurepg-entra[sqlalchemy]"
243
+ ```
244
+
245
+ ### Synchronous Engine
246
+
247
+ ```python
248
+ from sqlalchemy import create_engine
249
+ from azure_postgresql_auth.sqlalchemy import enable_entra_authentication # import library
250
+
251
+ with create_engine("postgresql+psycopg://your-server.postgres.database.azure.com/your_database") as engine:
252
+ # Enable Entra ID authentication
253
+ enable_entra_authentication(engine)
254
+
255
+ # Core usage
256
+ with engine.connect() as conn:
257
+
258
+ # ORM usage
259
+ from sqlalchemy.orm import sessionmaker
260
+ Session = sessionmaker(bind=engine)
261
+ ```
262
+
263
+ ### Asynchronous Engine
264
+
265
+ ```python
266
+ from sqlalchemy.ext.asyncio import create_async_engine
267
+ from azure_postgresql_auth.sqlalchemy import enable_entra_authentication_async # import library
268
+
269
+ async with create_async_engine("postgresql+psycopg://your-server.postgres.database.azure.com/your_database") as engine:
270
+ # Enable Entra ID authentication for async
271
+ enable_entra_authentication_async(engine)
272
+
273
+ # Async Core usage
274
+ async with engine.connect() as conn:
275
+
276
+ # Async ORM usage
277
+ from sqlalchemy.ext.asyncio import async_sessionmaker
278
+ AsyncSession = async_sessionmaker(engine, expire_on_commit=False)
279
+ ```
280
+
281
+ ## How It Works
282
+
283
+ ### Authentication Flow
284
+
285
+ 1. **Token Acquisition**: Uses Azure Identity libraries (`DefaultAzureCredential` by default) to acquire access tokens from Azure Entra ID
286
+ 2. **Automatic Refresh**: Tokens are automatically refreshed before each new database connection
287
+ 3. **Secure Transport**: Tokens are passed as passwords in PostgreSQL connection strings over SSL
288
+ 4. **Server Validation**: Azure Database for PostgreSQL validates the token and establishes the authenticated connection
289
+ 5. **User Mapping**: The token's user principal name (UPN) is mapped to a PostgreSQL user for authorization
290
+
291
+ ### Token Scopes
292
+
293
+ The package automatically requests the correct OAuth2 scopes:
294
+ - **Database scope**: `https://ossrdbms-aad.database.windows.net/.default` (primary)
295
+ - **Management scope**: `https://management.azure.com/.default` (fallback for managed identities)
296
+
297
+ ### Security Features
298
+
299
+ - **🔒 Token-based authentication**: No passwords stored or transmitted
300
+ - **⏰ Automatic expiration**: Tokens expire and are refreshed automatically
301
+ - **🛡️ SSL enforcement**: All connections require SSL encryption
302
+ - **🔑 Principle of least privilege**: Only database-specific scopes are requested
303
+ ---
304
+
305
+ ## Troubleshooting
306
+
307
+ ### Common Issues
308
+
309
+ **Authentication Errors**
310
+ ```bash
311
+ # Error: "password authentication failed"
312
+ # Solution: Ensure your Azure identity has been granted access to the database
313
+ # Run this SQL as a database administrator:
314
+ CREATE ROLE "your-user@your-domain.com" WITH LOGIN;
315
+ GRANT ALL PRIVILEGES ON DATABASE your_database TO "your-user@your-domain.com";
316
+ ```
317
+
318
+ **Connection Timeouts**
319
+ ```python
320
+ # Increase connection timeout for slow networks
321
+ conn = SyncEntraConnection.connect(
322
+ "postgresql://server:5432/db",
323
+ connect_timeout=30 # 30 seconds instead of default 10
324
+ )
325
+ ```
326
+
327
+ **Windows Async Issues**
328
+ ```python
329
+ # Fix Windows event loop compatibility
330
+ import asyncio
331
+ import sys
332
+
333
+ if sys.platform == "win32":
334
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
335
+ ```
336
+
337
+ ### Debug Logging
338
+
339
+ Enable debug logging to troubleshoot authentication issues:
340
+
341
+ ```python
342
+ import logging
343
+ logging.basicConfig(level=logging.DEBUG)
344
+
345
+ # This will show token acquisition and connection details
346
+ conn = SyncEntraConnection.connect("postgresql://server:5432/db")
347
+ ```
348
+
349
+ ---
350
+
351
+ ## Contributing
352
+
353
+ We welcome contributions! Please see [CONTRIBUTING.md](../CONTRIBUTING.md) for guidelines.
354
+
355
+
356
+ ---
357
+
358
+ ## License
359
+
360
+ This project is licensed under the MIT License - see the [LICENSE](../LICENSE) file for details.
@@ -0,0 +1,311 @@
1
+ # azurepg-entra: Azure Database for PostgreSQL Entra ID Authentication
2
+
3
+ This package provides seamless Azure Entra ID authentication for Python database drivers connecting to Azure Database for PostgreSQL. It supports both legacy and modern PostgreSQL drivers with automatic token management and connection pooling.
4
+
5
+ ## Features
6
+
7
+ - **🔐 Azure Entra ID Authentication**: Automatic token acquisition and refresh for secure database connections
8
+ - **🔄 Multi-Driver Support**: Works with psycopg2, psycopg3, and SQLAlchemy
9
+ - **⚡ Connection Pooling**: Built-in support for both synchronous and asynchronous connection pools
10
+ - **🏗️ Clean Architecture**: Simple package structure with `azure_postgresql_auth.psycopg2`, `azure_postgresql_auth.psycopg3`, and `azure_postgresql_auth.sqlalchemy`
11
+ - **🔄 Automatic Token Management**: Handles token acquisition, validation, and refresh automatically
12
+ - **🌐 Cross-platform**: Works on Windows, Linux, and macOS
13
+ - **📦 Flexible Installation**: Optional dependencies for different driver combinations
14
+
15
+ ## Installation
16
+
17
+ ### Basic Installation
18
+
19
+ Install the core package (includes Azure Identity dependencies only):
20
+ ```bash
21
+ pip install azurepg-entra
22
+ ```
23
+
24
+ ### Driver-Specific Installation
25
+
26
+ Choose the installation option based on which PostgreSQL drivers you need:
27
+
28
+ ```bash
29
+ # For psycopg3 (modern psycopg, recommended for new projects)
30
+ pip install "azurepg-entra[psycopg3]"
31
+
32
+ # For psycopg2 (legacy support)
33
+ pip install "azurepg-entra[psycopg2]"
34
+
35
+ # For SQLAlchemy with psycopg3 backend
36
+ pip install "azurepg-entra[sqlalchemy]"
37
+
38
+ # All database drivers combined
39
+ pip install "azurepg-entra[drivers]"
40
+
41
+ # Everything including development tools
42
+ pip install "azurepg-entra[all]"
43
+ ```
44
+
45
+ ### Development Installation
46
+
47
+ Install from source for development:
48
+ ```bash
49
+ git clone https://github.com/v-anarendra_microsoft/entra-id-integration-for-drivers.git
50
+ cd entra-id-integration-for-drivers/python
51
+
52
+ # Install with all dependencies for development
53
+ pip install -e ".[all]"
54
+
55
+ # Or install specific driver combinations
56
+ pip install -e ".[psycopg3,dev]"
57
+ ```
58
+
59
+ ## Configuration
60
+
61
+ ### Environment Variables
62
+
63
+ The samples use environment variables to configure database connections.
64
+
65
+ Copy `.env.example` into a `.env` file in the same directory and update the variables.
66
+ ```env
67
+ POSTGRES_SERVER=<your-server.postgres.database.azure.com>
68
+ POSTGRES_DATABASE=<your_database_name>
69
+ ```
70
+
71
+ ## Quick Start
72
+
73
+ ### Running the Samples
74
+
75
+ The repository includes comprehensive working examples in the `samples/` directory:
76
+
77
+ - **`samples/psycopg2/getting_started/`**: psycopg2 (legacy driver support)
78
+ - **`samples/psycopg3/getting_started/`**: psycopg3 examples (modern driver, recommended)
79
+ - **`samples/sqlalchemy/getting_started/`**: SQLAlchemy examples with psycopg3 backend
80
+
81
+ Configure your environment variables first, then run the samples:
82
+
83
+ ```bash
84
+ # Copy and configure environment
85
+ cp samples/psycopg3/getting_started/.env.example samples/psycopg3/getting_started/.env
86
+ # Edit .env with your Azure PostgreSQL server details
87
+
88
+ # Test psycopg2 (legacy driver)
89
+ python samples/psycopg2/getting_started/create_db_connection_psycopg2.py --mode both
90
+
91
+ # Test psycopg3 (modern driver, recommended)
92
+ python samples/psycopg3/getting_started/create_db_connection_psycopg.py --mode both
93
+
94
+ # Test SQLAlchemy
95
+ python samples/sqlalchemy/getting_started/create_db_connection_sqlalchemy.py --mode both
96
+ ```
97
+
98
+ ## Usage
99
+
100
+ Choose the driver that best fits your project needs:
101
+
102
+ - **psycopg3**: Modern PostgreSQL driver (recommended for new projects)
103
+ - **psycopg2**: Legacy PostgreSQL driver (for existing projects)
104
+ - **SQLAlchemy**: High-level ORM/Core interface
105
+
106
+ ---
107
+
108
+ ## psycopg2 Driver (Legacy Support)
109
+
110
+ > **Note**: psycopg2 is in maintenance mode. For new projects, consider using psycopg3 instead.
111
+
112
+ The psycopg2 integration provides synchronous connection support with Azure Entra ID authentication through connection pooling.
113
+
114
+ ### Installation
115
+ ```bash
116
+ pip install "azurepg-entra[psycopg2]"
117
+ ```
118
+
119
+ ### Connection Pooling (Recommended)
120
+
121
+ ```python
122
+ from azure_postgresql_auth.psycopg2 import EntraConnection # import library
123
+ from psycopg2 import pool # import to use pooling
124
+
125
+ with pool.ThreadedConnectionPool(
126
+ minconn=1,
127
+ maxconn=5,
128
+ host="your-server.postgres.database.azure.com",
129
+ database="your_database",
130
+ connection_factory=EntraConnection
131
+ ) as connection_pool:
132
+ ```
133
+
134
+ ### Direct Connection
135
+
136
+ ```python
137
+ from azure_postgresql_auth.psycopg2 import EntraConnection # import library
138
+
139
+ with EntraConnection(
140
+ "postgresql://your-server.postgres.database.azure.com:5432/your_database"
141
+ ) as conn
142
+ ```
143
+
144
+ ---
145
+
146
+ ## psycopg3 Driver (Recommended)
147
+
148
+ psycopg3 is the modern, actively developed PostgreSQL driver with native async support and better performance.
149
+
150
+ ### Installation
151
+ ```bash
152
+ pip install "azurepg-entra[psycopg3]"
153
+ ```
154
+
155
+ ### Synchronous Connection
156
+
157
+ ```python
158
+ from azure_postgresql_auth.psycopg3 import EntraConnection # import library
159
+ from psycopg_pool import ConnectionPool # import to use pooling
160
+
161
+ with ConnectionPool(
162
+ conninfo="postgresql://your-server.postgres.database.azure.com:5432/your_database",
163
+ connection_class=EntraConnection,
164
+ min_size=1, # keep at least 1 connection always open
165
+ max_size=5, # allow up to 5 concurrent connections
166
+ ) as pool
167
+ ```
168
+
169
+ ### Asynchronous Connection
170
+
171
+ ```python
172
+ from azure_postgresql_auth.psycopg3 import AsyncEntraConnection # import library
173
+ from psycopg_pool import AsyncConnectionPool # import to use pooling
174
+
175
+ async with AsyncConnectionPool(
176
+ conninfo="postgresql://your-server.postgres.database.azure.com:5432/your_database",
177
+ connection_class=AsyncEntraConnection,
178
+ min_size=1, # keep at least 1 connection always open
179
+ max_size=5, # allow up to 5 concurrent connections
180
+ ) as pool
181
+ ```
182
+
183
+ ---
184
+
185
+ ## SQLAlchemy Integration
186
+
187
+ SQLAlchemy integration uses psycopg3 as the backend driver with automatic Entra ID authentication through event listeners.
188
+
189
+ > **For more information**: See SQLAlchemy's documentation on [controlling how parameters are passed to the DBAPI connect function](https://docs.sqlalchemy.org/en/20/core/engines.html#controlling-how-parameters-are-passed-to-the-dbapi-connect-function).
190
+
191
+ ### Installation
192
+ ```bash
193
+ pip install "azurepg-entra[sqlalchemy]"
194
+ ```
195
+
196
+ ### Synchronous Engine
197
+
198
+ ```python
199
+ from sqlalchemy import create_engine
200
+ from azure_postgresql_auth.sqlalchemy import enable_entra_authentication # import library
201
+
202
+ with create_engine("postgresql+psycopg://your-server.postgres.database.azure.com/your_database") as engine:
203
+ # Enable Entra ID authentication
204
+ enable_entra_authentication(engine)
205
+
206
+ # Core usage
207
+ with engine.connect() as conn:
208
+
209
+ # ORM usage
210
+ from sqlalchemy.orm import sessionmaker
211
+ Session = sessionmaker(bind=engine)
212
+ ```
213
+
214
+ ### Asynchronous Engine
215
+
216
+ ```python
217
+ from sqlalchemy.ext.asyncio import create_async_engine
218
+ from azure_postgresql_auth.sqlalchemy import enable_entra_authentication_async # import library
219
+
220
+ async with create_async_engine("postgresql+psycopg://your-server.postgres.database.azure.com/your_database") as engine:
221
+ # Enable Entra ID authentication for async
222
+ enable_entra_authentication_async(engine)
223
+
224
+ # Async Core usage
225
+ async with engine.connect() as conn:
226
+
227
+ # Async ORM usage
228
+ from sqlalchemy.ext.asyncio import async_sessionmaker
229
+ AsyncSession = async_sessionmaker(engine, expire_on_commit=False)
230
+ ```
231
+
232
+ ## How It Works
233
+
234
+ ### Authentication Flow
235
+
236
+ 1. **Token Acquisition**: Uses Azure Identity libraries (`DefaultAzureCredential` by default) to acquire access tokens from Azure Entra ID
237
+ 2. **Automatic Refresh**: Tokens are automatically refreshed before each new database connection
238
+ 3. **Secure Transport**: Tokens are passed as passwords in PostgreSQL connection strings over SSL
239
+ 4. **Server Validation**: Azure Database for PostgreSQL validates the token and establishes the authenticated connection
240
+ 5. **User Mapping**: The token's user principal name (UPN) is mapped to a PostgreSQL user for authorization
241
+
242
+ ### Token Scopes
243
+
244
+ The package automatically requests the correct OAuth2 scopes:
245
+ - **Database scope**: `https://ossrdbms-aad.database.windows.net/.default` (primary)
246
+ - **Management scope**: `https://management.azure.com/.default` (fallback for managed identities)
247
+
248
+ ### Security Features
249
+
250
+ - **🔒 Token-based authentication**: No passwords stored or transmitted
251
+ - **⏰ Automatic expiration**: Tokens expire and are refreshed automatically
252
+ - **🛡️ SSL enforcement**: All connections require SSL encryption
253
+ - **🔑 Principle of least privilege**: Only database-specific scopes are requested
254
+ ---
255
+
256
+ ## Troubleshooting
257
+
258
+ ### Common Issues
259
+
260
+ **Authentication Errors**
261
+ ```bash
262
+ # Error: "password authentication failed"
263
+ # Solution: Ensure your Azure identity has been granted access to the database
264
+ # Run this SQL as a database administrator:
265
+ CREATE ROLE "your-user@your-domain.com" WITH LOGIN;
266
+ GRANT ALL PRIVILEGES ON DATABASE your_database TO "your-user@your-domain.com";
267
+ ```
268
+
269
+ **Connection Timeouts**
270
+ ```python
271
+ # Increase connection timeout for slow networks
272
+ conn = SyncEntraConnection.connect(
273
+ "postgresql://server:5432/db",
274
+ connect_timeout=30 # 30 seconds instead of default 10
275
+ )
276
+ ```
277
+
278
+ **Windows Async Issues**
279
+ ```python
280
+ # Fix Windows event loop compatibility
281
+ import asyncio
282
+ import sys
283
+
284
+ if sys.platform == "win32":
285
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
286
+ ```
287
+
288
+ ### Debug Logging
289
+
290
+ Enable debug logging to troubleshoot authentication issues:
291
+
292
+ ```python
293
+ import logging
294
+ logging.basicConfig(level=logging.DEBUG)
295
+
296
+ # This will show token acquisition and connection details
297
+ conn = SyncEntraConnection.connect("postgresql://server:5432/db")
298
+ ```
299
+
300
+ ---
301
+
302
+ ## Contributing
303
+
304
+ We welcome contributions! Please see [CONTRIBUTING.md](../CONTRIBUTING.md) for guidelines.
305
+
306
+
307
+ ---
308
+
309
+ ## License
310
+
311
+ This project is licensed under the MIT License - see the [LICENSE](../LICENSE) file for details.