Skip to content

fix: per-tenant AuthenticationRecord + InteractiveBrowserCredential in auth.py#46

Open
suyask-msft wants to merge 1 commit into
mainfrom
fix/auth-record-per-tenant
Open

fix: per-tenant AuthenticationRecord + InteractiveBrowserCredential in auth.py#46
suyask-msft wants to merge 1 commit into
mainfrom
fix/auth-record-per-tenant

Conversation

@suyask-msft
Copy link
Copy Markdown
Collaborator

Summary

Two related fixes to scripts/auth.py, combined because they touch overlapping code paths.

Changes

1. Per-tenant AuthenticationRecord (cross-tenant bug fix)

Previously auth.py stored the AuthenticationRecord at a single global path (dataverse_cli_auth_record.json). Because a record's home_account_id is tenant-bound, switching tenants overwrote the file and forced a full re-auth on the next switch-back — a popup loop for developers working across multiple tenants.

Record path now includes TENANT_ID:

dataverse_cli_auth_record_<tenant_id>.json

Smooth upgrade: _read_auth_record() falls back to the legacy global path on first run, so existing users keep their cached record. The next successful auth writes to the new per-tenant path. No user action required.

Same-tenant multi-env unchanged: MSAL's internal cache already holds multiple resource-scope access tokens per (user + tenant), so same-tenant users see no change.

2. InteractiveBrowserCredential instead of DeviceCodeCredential

Aligns auth.py with the rest of the dv-connect stack:

Stack Auth UX
PAC CLI (pac auth create) Interactive browser ✓
MCP proxy (@microsoft/dataverse mcp) Interactive browser ✓
auth.py Device code (outlier) — user must read a URL and type a code

After this PR, all three stacks present a consistent browser-popup sign-in experience. No more typing codes.

Industry convention (Azure SDK docs, MSAL guidance) recommends interactive browser as the default for workstation CLIs; device code is documented as a fallback for headless/SSH contexts. This change brings auth.py in line with that norm.

What stays the same

  • Service principal auth (CLIENT_ID + CLIENT_SECRET) — unchanged, still highest priority
  • Token caching via TokenCachePersistenceOptions — same cache name, same OS credential store
  • AuthenticationRecord persistence semantics — saved on first successful auth, reused by subsequent processes

Version bump

1.2.0 → 1.2.1 (PATCH — cross-tenant bug fix + UX alignment, no breaking change)

Test plan

  • python -c "import ast; ast.parse(...)" — syntax valid
  • python .github/evals/static_checks.py — passes (6 categories, 70 Python blocks)
  • python .github/evals/version_bump_check.py — passes
  • Manual: fresh workspace on Windows dev machine, run dv-connect, verify auth.py opens browser (not device code)
  • Manual: connect to env in tenant A, disconnect, connect to env in tenant B, switch back to tenant A — verify no re-auth prompt on switch-back (proves per-tenant record persistence)
  • Manual: confirm existing users with a legacy global record file don't re-auth on first run after upgrade

Notes

The change to InteractiveBrowserCredential has been discussed extensively in prior iterations (closed PR #45 explored this). The final call: align with the rest of the stack; don't introduce a device-code opt-in env var; in the rare cases where interactive browser fails (SSH / headless / WSL-no-forwarding), users can configure a service principal (the canonical non-interactive path Microsoft recommends).

…n auth.py

Two related auth.py fixes for the developer-box flow, combined because
they touch overlapping code paths.

1. Per-tenant AuthenticationRecord (cross-tenant bug fix)

Previously auth.py stored the AuthenticationRecord at a single global path
(dataverse_cli_auth_record.json). Because a record's home_account_id is
tenant-bound, switching tenants overwrote the file and forced a full
re-auth on the next switch-back. Now the record path includes TENANT_ID:

  dataverse_cli_auth_record_<tenant_id>.json

Existing users are handled gracefully: _read_auth_record() falls back to
the legacy global path on first run; the next successful auth writes to
the new per-tenant path. Same-tenant multi-env behavior is unchanged
(MSAL's internal cache already holds multiple resource-scope access tokens).

2. InteractiveBrowserCredential instead of DeviceCodeCredential

The dv-connect flow already uses interactive browser auth for PAC CLI and
the MCP proxy. auth.py was the outlier: it printed a URL and asked the user
to type a code. That was the only manual-typing step in the whole flow.
Switching to InteractiveBrowserCredential aligns auth.py with the rest of
the stack, matches industry convention (Azure CLI, az login, gh auth
login), and eliminates the code-typing UX.

Token caching unchanged: same TokenCachePersistenceOptions, same
AuthenticationRecord persistence (now per-tenant). No new env vars.

Version: 1.2.0 -> 1.2.1 (PATCH)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@suyask-msft suyask-msft requested a review from a team as a code owner April 23, 2026 05:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant