From 05f0d84fcc77cbd07b06bda60f21faac250c71b5 Mon Sep 17 00:00:00 2001 From: Vijay Bandari Date: Tue, 21 Apr 2026 17:51:00 -0700 Subject: [PATCH 1/3] Set auth header to Bearer to support service accounts --- lightdash/client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lightdash/client.py b/lightdash/client.py index 2e44768..09d65a2 100644 --- a/lightdash/client.py +++ b/lightdash/client.py @@ -33,6 +33,7 @@ def __init__(self, instance_url: str, access_token: str, project_uuid: str, conf self.instance_url = instance_url.rstrip('/') self.access_token = access_token self.project_uuid = project_uuid + self.auth_header = "Bearer" if access_token.startswith("ldsvc_") else "ApiKey" # Extract config values with defaults config = config or {} @@ -88,7 +89,7 @@ def _make_request( with httpx.Client( headers={ - "Authorization": f"ApiKey {self.access_token}", + "Authorization": f"{self.auth_header} {self.access_token}", "Accept": "application/json", }, timeout=self.timeout From 19813f92ff7ff33e5986d0589c551e5fcd677208 Mon Sep 17 00:00:00 2001 From: Jake Peterson <5532776+jpetey75@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:25:14 -0500 Subject: [PATCH 2/3] test: cover Bearer vs ApiKey auth scheme selection Adds unit coverage for the service-account auth change: ldsvc_ tokens use Bearer, ldpat_ and other tokens keep ApiKey. Construction makes no network call, so these run offline. Co-Authored-By: Claude Opus 4.8 --- tests/test_client.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/test_client.py diff --git a/tests/test_client.py b/tests/test_client.py new file mode 100644 index 0000000..f749849 --- /dev/null +++ b/tests/test_client.py @@ -0,0 +1,38 @@ +""" +Unit tests for Client construction. + +Covers the Authorization scheme selection: service account tokens (``ldsvc_``) +authenticate with ``Bearer`` while personal access tokens and anything else use +``ApiKey`` — matching the Lightdash backend auth middleware (issue #17). +""" + +import pytest +from lightdash import Client + + +def _client(token: str) -> Client: + # Construction makes no network call, so a dummy URL/project is fine. + return Client( + instance_url="https://example.lightdash.cloud", + access_token=token, + project_uuid="00000000-0000-0000-0000-000000000000", + ) + + +class TestAuthHeaderScheme: + def test_service_account_token_uses_bearer(self): + """ldsvc_ tokens must use the Bearer scheme.""" + assert _client("ldsvc_abc123").auth_header == "Bearer" + + def test_personal_access_token_uses_apikey(self): + """ldpat_ tokens keep the ApiKey scheme (unchanged behaviour).""" + assert _client("ldpat_abc123").auth_header == "ApiKey" + + def test_unprefixed_token_defaults_to_apikey(self): + """Any other token defaults to ApiKey, preserving backwards compatibility.""" + assert _client("legacy-token").auth_header == "ApiKey" + + def test_authorization_header_value(self): + """The composed Authorization header uses the selected scheme.""" + c = _client("ldsvc_abc123") + assert f"{c.auth_header} {c.access_token}" == "Bearer ldsvc_abc123" From 9a13cef66155615c04830429372639ec04571463 Mon Sep 17 00:00:00 2001 From: Jake Peterson <5532776+jpetey75@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:27:11 -0500 Subject: [PATCH 3/3] docs: note service account token support in README Co-Authored-By: Claude Opus 4.8 --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 50f2481..e10a595 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,10 @@ client = Client( ) ``` +`access_token` accepts both personal access tokens (`ldpat_…`) and service +account tokens (`ldsvc_…`); the SDK selects the correct authentication scheme +automatically. + ## Development ### Prerequisites