Skip to content

feat(sdk/python): add OIDC auth support for Python SDK#1201

Draft
arpad-csepi wants to merge 13 commits intomainfrom
feat/python-sdk-oidc-support
Draft

feat(sdk/python): add OIDC auth support for Python SDK#1201
arpad-csepi wants to merge 13 commits intomainfrom
feat/python-sdk-oidc-support

Conversation

@arpad-csepi
Copy link
Copy Markdown
Member

@arpad-csepi arpad-csepi commented Mar 27, 2026

This PR adds OAuth 2.0 / OIDC authentication to the Directory Python SDK so gRPC calls can send a Bearer access token when auth_mode is oauth_pkce.

Supports:

  • interactive browser login (Authorization Code + PKCE) with a loopback callback
  • non-interactive access via a pre-provisioned token
  • machine / CI flows via the client credentials grant

Configuration is extended with OIDC/OAuth fields: issuer, client id/secret, redirect URI, callback port, auth timeout, scopes, optional static access token, and machine client settings (id, secret, secret file, scopes, optional token endpoint) with the corresponding DIRECTORY_CLIENT_* environment variable wiring for these options.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 27, 2026

The latest Buf updates on your PR. Results from workflow Buf CI / verify-proto (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed⏩ skipped⏩ skipped✅ passedApr 2, 2026, 9:50 PM

@arpad-csepi arpad-csepi force-pushed the feat/python-sdk-oidc-support branch from 4855aa0 to efd355c Compare March 27, 2026 16:07
@github-actions github-actions bot added the size/L Denotes a PR that changes 1000-1999 lines label Mar 27, 2026
@arpad-csepi arpad-csepi marked this pull request as ready for review March 27, 2026 16:57
@arpad-csepi arpad-csepi requested a review from a team as a code owner March 27, 2026 16:57
@arpad-csepi arpad-csepi force-pushed the feat/python-sdk-oidc-support branch 2 times, most recently from f0e9314 to c93c2a8 Compare March 31, 2026 18:01
@arpad-csepi arpad-csepi marked this pull request as draft March 31, 2026 18:02
@arpad-csepi arpad-csepi changed the title feat(sdk): add OIDC auth support for Python SDK feat(sdk/python): add OIDC auth support for Python SDK Mar 31, 2026
arpad-csepi and others added 11 commits April 2, 2026 11:15
Signed-off-by: Árpád Csepi <csepi.arpad@outlook.com>
Signed-off-by: Árpád Csepi <csepi.arpad@outlook.com>
Signed-off-by: Árpád Csepi <csepi.arpad@outlook.com>
Signed-off-by: Árpád Csepi <csepi.arpad@outlook.com>
Signed-off-by: Árpád Csepi <csepi.arpad@outlook.com>
Signed-off-by: Árpád Csepi <csepi.arpad@outlook.com>
Signed-off-by: Árpád Csepi <csepi.arpad@outlook.com>
Signed-off-by: Tibor Kircsi <tkircsi@cisco.com>
Signed-off-by: Árpád Csepi <csepi.arpad@outlook.com>
Signed-off-by: Árpád Csepi <csepi.arpad@outlook.com>
Signed-off-by: Árpád Csepi <csepi.arpad@outlook.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Signed-off-by: Árpád Csepi <21104922+arpad-csepi@users.noreply.github.com>
@tkircsi tkircsi force-pushed the feat/python-sdk-oidc-support branch from c93c2a8 to 2a44a8d Compare April 2, 2026 09:15
tkircsi and others added 2 commits April 2, 2026 14:30
import json
import os
import tempfile
import unittest

Check notice

Code scanning / CodeQL

Module is imported with 'import' and 'import from' Note test

Module 'unittest' is imported with both 'import' and 'import from'.

Copilot Autofix

AI 3 days ago

To fix the problem, keep only one style of importing the unittest module and adjust uses of mock accordingly. Since unittest is already imported as a module and is also used as unittest.TestCase and unittest.main(), the cleanest fix is to remove from unittest import mock and refer to unittest.mock everywhere instead of mock.

Concretely, in sdk/dir-py/agntcy/dir_sdk/client/test_oidc_auth.py:

  • Remove the line from unittest import mock.
  • Replace all occurrences of mock. with unittest.mock.. The shown code uses mock.patch.dict and mock.patch, so these should become unittest.mock.patch.dict and unittest.mock.patch. This preserves behavior while eliminating the duplicate import style.

No additional methods, definitions, or imports are needed beyond updating these references.

Suggested changeset 1
sdk/dir-py/agntcy/dir_sdk/client/test_oidc_auth.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/sdk/dir-py/agntcy/dir_sdk/client/test_oidc_auth.py b/sdk/dir-py/agntcy/dir_sdk/client/test_oidc_auth.py
--- a/sdk/dir-py/agntcy/dir_sdk/client/test_oidc_auth.py
+++ b/sdk/dir-py/agntcy/dir_sdk/client/test_oidc_auth.py
@@ -8,7 +8,6 @@
 import tempfile
 import unittest
 from datetime import UTC, datetime, timedelta
-from unittest import mock
 
 from agntcy.dir_sdk.client import Client, Config
 from agntcy.dir_sdk.client.oauth_pkce import OAuthTokenHolder
@@ -17,7 +16,7 @@
 
 class OIDCAuthConfigTests(unittest.TestCase):
     def test_load_from_env_uses_auth_token(self) -> None:
-        with mock.patch.dict(
+        with unittest.mock.patch.dict(
             "os.environ",
             {
                 "DIRECTORY_CLIENT_AUTH_TOKEN": "primary-token",
@@ -30,7 +29,7 @@
         self.assertEqual(config.oidc_access_token, "primary-token")
 
     def test_load_from_env_ignores_legacy_token_names(self) -> None:
-        with mock.patch.dict(
+        with unittest.mock.patch.dict(
             "os.environ",
             {
                 "DIRECTORY_CLIENT_OIDC_ACCESS_TOKEN": "legacy-token",
@@ -51,7 +50,7 @@
 
     def test_token_cache_uses_dirctl_path(self) -> None:
         with tempfile.TemporaryDirectory() as tmp_dir:
-            with mock.patch.dict("os.environ", {"XDG_CONFIG_HOME": tmp_dir}, clear=True):
+            with unittest.mock.patch.dict("os.environ", {"XDG_CONFIG_HOME": tmp_dir}, clear=True):
                 cache = TokenCache()
 
         self.assertEqual(
@@ -69,13 +68,13 @@
         )
 
         with (
-            mock.patch(
+            unittest.mock.patch(
                 "agntcy.dir_sdk.client.client.fetch_openid_configuration",
             ) as fetch_mock,
-            mock.patch(
+            unittest.mock.patch(
                 "agntcy.dir_sdk.client.client.run_loopback_pkce_login",
             ) as login_mock,
-            mock.patch(
+            unittest.mock.patch(
                 "agntcy.dir_sdk.client.client.TokenCache.get_valid_token",
                 return_value=None,
             ),
EOF
@@ -8,7 +8,6 @@
import tempfile
import unittest
from datetime import UTC, datetime, timedelta
from unittest import mock

from agntcy.dir_sdk.client import Client, Config
from agntcy.dir_sdk.client.oauth_pkce import OAuthTokenHolder
@@ -17,7 +16,7 @@

class OIDCAuthConfigTests(unittest.TestCase):
def test_load_from_env_uses_auth_token(self) -> None:
with mock.patch.dict(
with unittest.mock.patch.dict(
"os.environ",
{
"DIRECTORY_CLIENT_AUTH_TOKEN": "primary-token",
@@ -30,7 +29,7 @@
self.assertEqual(config.oidc_access_token, "primary-token")

def test_load_from_env_ignores_legacy_token_names(self) -> None:
with mock.patch.dict(
with unittest.mock.patch.dict(
"os.environ",
{
"DIRECTORY_CLIENT_OIDC_ACCESS_TOKEN": "legacy-token",
@@ -51,7 +50,7 @@

def test_token_cache_uses_dirctl_path(self) -> None:
with tempfile.TemporaryDirectory() as tmp_dir:
with mock.patch.dict("os.environ", {"XDG_CONFIG_HOME": tmp_dir}, clear=True):
with unittest.mock.patch.dict("os.environ", {"XDG_CONFIG_HOME": tmp_dir}, clear=True):
cache = TokenCache()

self.assertEqual(
@@ -69,13 +68,13 @@
)

with (
mock.patch(
unittest.mock.patch(
"agntcy.dir_sdk.client.client.fetch_openid_configuration",
) as fetch_mock,
mock.patch(
unittest.mock.patch(
"agntcy.dir_sdk.client.client.run_loopback_pkce_login",
) as login_mock,
mock.patch(
unittest.mock.patch(
"agntcy.dir_sdk.client.client.TokenCache.get_valid_token",
return_value=None,
),
Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Denotes a PR that changes 1000-1999 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants