Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

auth.py update suggestion for multiple auth_record.json on different tenant/environments #86

Copy link
Copy link

Description

@tchinnin
Issue body actions

_AUTH_RECORD_PATH is module-level constant — shared across all projects, causes device code loop when switching tenants

Problem

auth.py computes _AUTH_RECORD_PATH once at module import time, before any .env is loaded:

_AUTH_RECORD_PATH = Path(os.environ.get("LOCALAPPDATA") or Path.home()) / ".IdentityService" / "dataverse_cli_auth_record.json"

This means every project on the machine shares the same dataverse_cli_auth_record.json file, regardless of tenant or environment.

Impact when working across multiple projects/clients in parallel:

  1. Project A authenticates → record written for tenant aaa / user alice@client-a.com
  2. Developer switches to Project B (tenant bbb, user bob@client-b.com) → DeviceCodeCredential loads the stale record from Project A
  3. The credential silently attempts a refresh for the wrong tenant/account
  4. When the refresh fails and a new device code is issued, the browser picks up the code, routes to the account picker, the user selects the correct account — but Microsoft rejects it because the tenant in the code doesn't match → infinite redirect loop back to the device code entry page

The bug is not obvious to diagnose: the error manifests as a browser redirect loop, not a clear authentication failure.

Proposed fix

Make the path a function, computed lazily after load_env() has run, using TENANT_ID and the Dataverse hostname as a disambiguating slug:

def _auth_record_path() -> Path:
    tenant_id = os.environ.get("TENANT_ID", "")
    dataverse_url = os.environ.get("DATAVERSE_URL", "")
    base = Path(os.environ.get("LOCALAPPDATA") or Path.home()) / ".IdentityService"

    if tenant_id and dataverse_url:
        tenant_short = tenant_id.split("-")[0]
        try:
            from urllib.parse import urlparse
            host = urlparse(dataverse_url).hostname or ""
            env_slug = host.split(".")[0]  # e.g. "contoso-dev" from "contoso-dev.crm4.dynamics.com"
        except Exception:
            env_slug = ""
        slug = f"_{tenant_short}_{env_slug}" if env_slug else f"_{tenant_short}"
        return base / f"dataverse_cli_auth_record{slug}.json"

    return base / "dataverse_cli_auth_record.json"  # safe fallback

Then replace every reference to _AUTH_RECORD_PATH with a call to _auth_record_path() — always after load_env() has been called.

Result: each environment gets its own record (e.g. dataverse_cli_auth_record_be91cf8c_contoso-dev.json), silent refresh works per-project, and parallel multi-client setups no longer interfere with each other.

Environment

  • macOS (same issue applies on Linux; Windows uses LOCALAPPDATA which is also per-user but the collision still occurs)
  • Multiple Dataverse environments across different tenants on the same machine
  • azure-identity device code flow with TokenCachePersistenceOptions
Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.