Auth¶
The auth surface in mixpanel_headless is organized around three independent axes — Account, Project, Workspace — with three first-class account types, a single resolver, fluent in-session switching via Workspace.use(), and a Cowork bridge for remote authentication.
Explore on DeepWiki
Ask questions about account types, session axes, OAuth, the Cowork bridge, or in-session switching.
Overview¶
import mixpanel_headless as mp
# Construct a Workspace from active config
ws = mp.Workspace()
# Override per Workspace (env > param > target > bridge > [active] > default_project)
ws = mp.Workspace(account="team", project="3713224")
ws = mp.Workspace(target="ecom")
ws = mp.Workspace(session=mp.Session(account=..., project=..., workspace=...))
# In-session switching — fluent, O(1), no re-auth on project swap
ws.use(project="3018488").events()
ws.use(account="personal").events() # rebuilds auth header; preserves underlying HTTP client
ws.use(target="ecom").events() # applies all three axes atomically
ws.use(workspace=3448414).events()
# Functional namespaces (also re-exported as mp.accounts / mp.session / mp.targets)
summaries = mp.accounts.list()
mp.accounts.use("team")
active = mp.session.show() # ActiveSession
mp.targets.add("ecom", account="team", project="3018488", workspace=3448414)
See Configuration for the full setup walkthrough.
Account Types¶
Account is a Pydantic discriminated union over three first-class variants. The type field selects the variant; each variant carries the credentials it needs.
from mixpanel_headless import (
Account, # discriminated union type
ServiceAccount, # type == "service_account"
OAuthBrowserAccount, # type == "oauth_browser"
OAuthTokenAccount, # type == "oauth_token"
AccountType, # Literal["service_account" | "oauth_browser" | "oauth_token"]
Region, # Literal["us" | "eu" | "in"]
)
account: Account = ServiceAccount(
name="team",
region="us",
default_project="3018488",
username="team-mp...",
secret="...",
)
if isinstance(account, ServiceAccount):
print(f"SA {account.name} → project {account.default_project}")
ServiceAccount¶
Long-lived HTTP Basic Auth credentials. Best for CI / scripts / unattended automation.
mixpanel_headless.ServiceAccount
¶
Bases: _AccountBase
Basic-auth service account credentials.
Long-lived credentials provisioned via the Mixpanel UI ("Service Accounts"
section). Encodes username:secret as base64 for the Authorization
header per the Mixpanel REST API spec.
Example
type
class-attribute
instance-attribute
¶
Discriminator value for this variant.
username
instance-attribute
¶
Service account username (e.g. sa.demo).
secret
instance-attribute
¶
Service account secret. Redacted in repr/str via Pydantic.
auth_header
¶
Return the Authorization header value for HTTP requests.
| PARAMETER | DESCRIPTION |
|---|---|
token_resolver
|
Ignored for service accounts (kept for signature parity with the other variants).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The |
Source code in src/mixpanel_headless/_internal/auth/account.py
is_long_lived
¶
Return whether this account survives across restarts without refresh.
| RETURNS | DESCRIPTION |
|---|---|
bool
|
|
OAuthBrowserAccount¶
PKCE browser flow; access/refresh tokens persisted at ~/.mp/accounts/{name}/tokens.json and auto-refreshed on expiry.
mixpanel_headless.OAuthBrowserAccount
¶
Bases: _AccountBase
OAuth account authenticated via PKCE browser flow.
The Account itself carries no secret — tokens are persisted at
~/.mp/accounts/{name}/tokens.json and produced on demand by a
:class:TokenResolver.
Example
type
class-attribute
instance-attribute
¶
Discriminator value for this variant.
auth_header
¶
Return the Authorization header value for HTTP requests.
| PARAMETER | DESCRIPTION |
|---|---|
token_resolver
|
Resolver responsible for loading + refreshing the on-disk token. Required.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The |
Source code in src/mixpanel_headless/_internal/auth/account.py
is_long_lived
¶
Return whether this account survives across restarts without refresh.
| RETURNS | DESCRIPTION |
|---|---|
bool
|
|
OAuthTokenAccount¶
Static bearer token (CI / agents) — supplied inline or via an env var (token_env).
mixpanel_headless.OAuthTokenAccount
¶
Bases: _AccountBase
OAuth account using a static bearer token (CI, agents, ephemeral runs).
Exactly one of token (inline SecretStr) or token_env (env-var
name) must be provided — never both, never neither. This is enforced at
construction time by :meth:_validate_exactly_one_token_source.
Example
type
class-attribute
instance-attribute
¶
Discriminator value for this variant.
token
class-attribute
instance-attribute
¶
Inline static bearer token (mutually exclusive with token_env).
token_env
class-attribute
instance-attribute
¶
Env-var name to read the bearer from at resolution time.
auth_header
¶
Return the Authorization header value for HTTP requests.
| PARAMETER | DESCRIPTION |
|---|---|
token_resolver
|
Resolver responsible for materializing the token
(from inline
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The |
Source code in src/mixpanel_headless/_internal/auth/account.py
is_long_lived
¶
Return whether this account survives across restarts without refresh.
| RETURNS | DESCRIPTION |
|---|---|
bool
|
|
Session Axes¶
A Session is the immutable resolved state for a single Workspace at construction time — account, project, optional workspace, and the auth headers they generate.
mixpanel_headless.Session
¶
Bases: BaseModel
Immutable in-memory tuple of (Account, Project, optional WorkspaceRef).
Holds the resolved auth/scope state for a single chain of API calls.
Switching to a different account, project, or workspace produces a new
Session via :meth:replace; the original is never mutated.
Workspace is optional: a session with workspace=None lazy-resolves
on the first workspace-scoped API call (per FR-025).
account
instance-attribute
¶
Resolved account (one of the three discriminated variants).
workspace
class-attribute
instance-attribute
¶
Resolved workspace; None triggers lazy resolution on first use.
headers
class-attribute
instance-attribute
¶
Custom HTTP headers attached at resolution time.
Populated from [settings].custom_header and/or bridge.headers.
Never read from os.environ after Session construction (per FR-014).
Wrapped in :class:types.MappingProxyType after validation, so any
in-place mutation (session.headers["X"] = "Y") raises
:class:TypeError instead of silently sharing state across
sessions. Consumers that need a mutable copy should use
dict(session.headers).
project_id
property
¶
Return the project's numeric string ID.
| RETURNS | DESCRIPTION |
|---|---|
str
|
|
workspace_id
property
¶
Return the workspace ID if set, else None.
| RETURNS | DESCRIPTION |
|---|---|
int | None
|
|
region
property
¶
Return the account's region.
| RETURNS | DESCRIPTION |
|---|---|
Region
|
|
auth_header
¶
Return the Authorization header for HTTP requests.
| PARAMETER | DESCRIPTION |
|---|---|
token_resolver
|
Required for OAuth accounts; ignored for
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The header value ( |
Source code in src/mixpanel_headless/_internal/auth/session.py
replace
¶
replace(
*,
account: Account | None = None,
project: Project | None = None,
workspace: WorkspaceRef | None | _SentinelType = _SENTINEL,
headers: Mapping[str, str] | _SentinelType = _SENTINEL,
) -> Session
Return a new Session with the supplied axes swapped in.
Workspace and headers use a sentinel because None (resp. {})
is a valid replacement value, semantically distinct from "do not
touch this axis".
| PARAMETER | DESCRIPTION |
|---|---|
account
|
Replacement account; omitted preserves the current value.
TYPE:
|
project
|
Replacement project; omitted preserves the current value.
TYPE:
|
workspace
|
Replacement workspace;
TYPE:
|
headers
|
Replacement headers map;
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Session
|
A new :class: |
Source code in src/mixpanel_headless/_internal/auth/session.py
mixpanel_headless.Project
¶
Bases: BaseModel
Mixpanel project reference.
Project IDs come from the Mixpanel API as numeric strings. timezone
and organization_id are populated when the resolver has access to
a /me response; both are optional.
id
instance-attribute
¶
Numeric project ID (Mixpanel's wire format is a digit string).
name
class-attribute
instance-attribute
¶
Display name from /me, when known.
organization_id
class-attribute
instance-attribute
¶
Owning organization ID from /me, when known.
timezone
class-attribute
instance-attribute
¶
Project timezone (e.g. "US/Pacific") from /me, when known.
mixpanel_headless.WorkspaceRef
¶
Bases: BaseModel
Mixpanel workspace reference (cohort/dashboard scoping unit).
The data model is named WorkspaceRef to avoid colliding with the
public Workspace facade class. Public re-export keeps the
WorkspaceRef name.
The optional project_id lets a :class:Session cross-check that the
workspace actually belongs to the bound project — every workspace lives
inside exactly one project, and routing a workspace ID to the wrong
project returns 400/404 deep inside the API call rather than at session
construction. When populated (typically from a /me enumeration), the
session-level model_validator raises :class:ValueError on mismatch
instead of letting the bug surface as an HTTP error mid-query.
id
instance-attribute
¶
Positive integer workspace ID assigned by Mixpanel.
name
class-attribute
instance-attribute
¶
Display name from /me or /projects/{pid}/workspaces/public.
is_default
class-attribute
instance-attribute
¶
Whether this is the project's default workspace, when known.
project_id
class-attribute
instance-attribute
¶
Owning project ID, when known.
Populated by /me enumeration paths so :class:Session can verify
project ↔ workspace coupling. Left None when the workspace was
constructed from a bare ID (e.g. MP_WORKSPACE_ID=N) — in that
case the cross-check degrades to "trust the caller" rather than raising
a spurious mismatch error.
mixpanel_headless.auth_types.ActiveSession
¶
Bases: BaseModel
Persisted shape of the [active] block in ~/.mp/config.toml.
Only account and workspace live in [active]. Project lives
on the account itself as Account.default_project — switching
accounts implicitly switches projects. Unknown keys (including
project) are rejected by extra="forbid".
Both fields are optional — environment variables or per-command flags can supply each one independently.
Workspace.use() — In-Session Switching¶
Workspace.use() is the only in-session switching method. It returns self for fluent chaining and preserves the underlying httpx.Client and per-account /me cache across switches, so cross-project / cross-account iteration is O(1) per turn.
import mixpanel_headless as mp
ws = mp.Workspace() # active session
# In-session switching (returns self for chaining)
ws.use(account="team") # implicitly clears workspace
ws.use(project="3018488")
ws.use(workspace=3448414)
ws.use(target="ecom") # apply all three at once
# Persist the new state
ws.use(project="3018488", persist=True) # writes account.default_project; [active] only stores account + workspace
# Fluent chain
result = ws.use(project="3018488").segmentation(
"Login", from_date="2026-04-01", to_date="2026-04-21"
)
Switching the active account clears the workspace (workspaces are project-scoped). The project re-resolves on account swap via env > explicit > new account's default_project. There is no silent cross-axis fallback: if an axis can't be resolved on the new account, use() raises ConfigError.
Swap one or more session axes in place; return self for chaining.
target= is mutually exclusive with account=/project=/
workspace=. The HTTP transport is preserved across all switches
(per Research R5).
When account= is supplied, the project axis re-resolves through
the FR-017 chain ending at the new account's default_project
(env MP_PROJECT_ID > explicit project= > new account's
default_project). If no source provides a project, the call
raises :class:ConfigError per FR-033 — the prior session's
project is NEVER carried forward across an account swap because
cross-account project access is not guaranteed. The workspace
axis is cleared on account swap (workspaces are project-scoped;
the prior workspace doesn't apply to the new project) — explicit
workspace= or MP_WORKSPACE_ID env override is honored.
| PARAMETER | DESCRIPTION |
|---|---|
account
|
Replacement account name.
TYPE:
|
project
|
Replacement project ID.
TYPE:
|
workspace
|
Replacement workspace ID.
TYPE:
|
target
|
Apply this target's three axes atomically.
TYPE:
|
persist
|
When
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Workspace
|
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
Mutually exclusive args, or referenced name missing. |
OAuthError
|
New auth header construction fails (atomic on success). |
ConfigError
|
|
Source code in src/mixpanel_headless/workspace.py
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 | |
Snapshot mode (parallel iteration)¶
For parallel cross-project iteration, snapshot the resolved Session and construct a fresh Workspace per task:
from concurrent.futures import ThreadPoolExecutor
import mixpanel_headless as mp
ws = mp.Workspace()
sessions = [
ws.session.replace(project=mp.Project(id=p.id))
for p in ws.projects()
]
def event_count(s: mp.Session) -> int:
return len(mp.Workspace(session=s).events())
with ThreadPoolExecutor(max_workers=4) as pool:
counts = list(pool.map(event_count, sessions))
Functional Namespaces¶
The auth surface exposes three module-level namespaces re-exported from mixpanel_headless. These are the canonical Python API for managing accounts, the active session, and saved targets.
mp.accounts¶
Account lifecycle: register, switch, probe, OAuth flows, bridge export. The login_unified orchestrator below collapses the explicit add + login pair into a single conversational call (the Python entry point behind mp login).
mixpanel_headless.accounts
¶
Public mp.accounts namespace.
Thin wrapper around :class:~mixpanel_headless._internal.config.ConfigManager
exposing account CRUD, switching, and probing operations as the canonical
Python API for mp account ... CLI commands and the plugin's
auth_manager.py.
Reference: specs/042-auth-architecture-redesign/contracts/python-api.md §5.
list
¶
Return all configured accounts as AccountSummary records.
| RETURNS | DESCRIPTION |
|---|---|
list[AccountSummary]
|
Sorted-by-name list of summaries. |
Source code in src/mixpanel_headless/accounts.py
add
¶
add(
name: str | None = None,
*,
type: AccountType,
region: Region | None = None,
default_project: str | None = None,
username: str | None = None,
secret: SecretStr | str | None = None,
token: SecretStr | str | None = None,
token_env: str | None = None,
derive_name: bool = False,
) -> AccountSummary
Add a new account.
Per 043 FR-001, default_project is OPTIONAL for every account
type at add-time. Service-account and oauth_token callers can
backfill it later via mp project use ID (or the mp login
orchestrator's project picker). For oauth_browser the value is
additionally backfilled by login(name) from the /me lookup
when no explicit project was set at add-time.
Per FR-045, the first account added auto-promotes to
[active].account. Subsequent accounts do not.
Derived naming (specs/043-frictionless-auth)¶
Pass derive_name=True (and leave name=None) to have the
function fetch /me against the supplied credentials and pick a
name from the first organization via
:func:naming.default_account_name. derive_name=True together
with an explicit name= is a logic error and raises
TypeError to surface the conflict at the caller. Derivation is
only supported for service_account and oauth_token — the
oauth_browser path needs the PKCE flow to obtain credentials,
which lives in mp login / login_unified (not here).
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Account name (must match
TYPE:
|
type
|
One of
TYPE:
|
region
|
One of
TYPE:
|
default_project
|
Numeric project ID. Optional for every type;
populated later via
TYPE:
|
username
|
Required for
TYPE:
|
secret
|
Required for
TYPE:
|
token
|
For
TYPE:
|
token_env
|
For
TYPE:
|
derive_name
|
When
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AccountSummary
|
class: |
| RAISES | DESCRIPTION |
|---|---|
TypeError
|
|
ConfigError
|
Validation failure, duplicate name,
|
Source code in src/mixpanel_headless/accounts.py
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | |
update
¶
update(
name: str,
*,
region: Region | None = None,
default_project: str | None = None,
username: str | None = None,
secret: SecretStr | str | None = None,
token: SecretStr | str | None = None,
token_env: str | None = None,
) -> AccountSummary
Update fields on an existing account in place.
Type cannot be changed via this function (remove + re-add for that).
Type-incompatible fields raise ConfigError.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Account to update.
TYPE:
|
region
|
New region.
TYPE:
|
default_project
|
New
TYPE:
|
username
|
New username (service_account only).
TYPE:
|
secret
|
New secret (service_account only).
TYPE:
|
token
|
New inline token (oauth_token only).
TYPE:
|
token_env
|
New env-var name (oauth_token only).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Updated
|
class:
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
Account not found, type-incompatible field, or validation failure. |
Source code in src/mixpanel_headless/accounts.py
remove
¶
Remove an account.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Account name.
TYPE:
|
force
|
When
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[str]
|
List of orphaned target names (empty unless |
list[str]
|
the account had references). |
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
Missing account. |
AccountInUseError
|
Referenced and |
Source code in src/mixpanel_headless/accounts.py
use
¶
Switch the active account, clearing any prior workspace pin.
The new account becomes [active].account and any prior
[active].workspace is dropped — workspaces are project-scoped, so
a leftover workspace ID from a different account would resolve to a
foreign workspace (or a 404) on the next Workspace() construction.
Project lives on the account itself as
:attr:Account.default_project, so it travels with the new account
automatically — no separate project axis to reset.
Both writes happen in a single _mutate() transaction so the
next process never sees a half-swapped state.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Account to make active.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
Account does not exist. |
Source code in src/mixpanel_headless/accounts.py
show
¶
Return the named account summary, or the active one if no name given.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Account name; if
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AccountSummary
|
class: |
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
Account not found OR no active account configured. |
Source code in src/mixpanel_headless/accounts.py
test
¶
Probe /me for the named account and return the structured result.
Resolves the named account (or active account when name is None),
constructs a short-lived :class:MixpanelAPIClient against /me,
and reports whether the credentials are accepted plus the
authenticated user identity / accessible-project count from the
response body.
Never raises — every failure mode (account not found, missing
credentials, OAuth refresh failure, HTTP error) is captured in
result.error so the CLI can render a structured failure message
and downstream tooling can color accounts as
needs_login / needs_token based on the error string.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Account to test;
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AccountTestResult
|
class: |
AccountTestResult
|
on success, or |
Source code in src/mixpanel_headless/accounts.py
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 | |
login
¶
Run the OAuth browser flow for an oauth_browser account.
Drives the full PKCE login dance:
- Validate
nameresolves to anoauth_browseraccount. - Run :meth:
OAuthFlow.login(PKCE + browser callback + token exchange). - Persist the resulting tokens atomically to
~/.mp/accounts/{name}/tokens.json. - Probe
/meto capture the authenticated user identity and (when missing) backfillaccount.default_projectwith the first accessible project.
The browser is opened by default; pass open_browser=False to
skip the call (useful for headless environments where the user copies
the authorization URL manually).
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Account name (must be
TYPE:
|
open_browser
|
Whether to launch the system browser. When False,
the authorize URL is printed to stderr for manual copy
(CLI flag:
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
An
|
class:
TYPE:
|
OAuthLoginResult
|
token expiry, and (best-effort) authenticated user identity. |
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
|
OAuthError
|
Any leg of the PKCE flow fails (registration, browser, callback, token exchange). |
Source code in src/mixpanel_headless/accounts.py
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 | |
login_unified
¶
login_unified(
*,
name: str | None = None,
region: Region | None = None,
project: str | None = None,
account_type: AccountType | None = None,
no_browser: bool = False,
secret_stdin: bool = False,
token_env: str | None = None,
service_account: bool = False,
project_picker: ProjectPicker | None = None,
progress: ProgressFactory | None = None,
) -> AccountSummary
Add and activate a Mixpanel account in one orchestrated call.
The conversational entry point for mp login. Composes the helpers
landed in earlier 043 commits (region probe, name derivation, SA
project relaxation) with the existing PKCE flow into a single call
that goes from "no config" to "ready to query".
Auth-type detection priority¶
account_typeparameter (explicit override).token_envset →oauth_token.MP_USERNAME+MP_SECRETenv both set →service_account.MP_OAUTH_TOKENenv set →oauth_token.- Default →
oauth_browser.
Project-selection priority (applied AFTER /me)¶
projectparameter (must exist in/me).MP_PROJECT_IDenv (warn-and-fall-through if missing from/me).- Single project in
/me→ auto-pick. - Caller-supplied
project_pickercallback (CLI provides one; library raisesConfigErrorE-8 when no callback is supplied).
Region resolution¶
oauth_browser:region(default"us") committed before the PKCE redirect; cross-checked against the picked project'sdomainafter the callback.service_account/oauth_token: whenregion is None, probesus → eu → inagainst/meuntil first 200.
Re-login (when an existing account matches the resolved name)¶
- Refreshes tokens (oauth_browser) or updates credentials (SA / token).
default_projectis preserved;project/MP_PROJECT_IDare ignored on this path (E-5 informational stderr note).- Region change → refused (E-3).
- Auth-type change → refused (E-4).
Output¶
Progress narration (region-probe attempts, the E-5 re-login note)
is written to stderr via :func:_narrate. Library callers who
want it suppressed can redirect the parent process's stderr;
the function does not currently expose a programmatic
narrate=False toggle.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Explicit local account name. Wins over derived names.
TYPE:
|
region
|
Explicit region.
TYPE:
|
project
|
Explicit project ID. Must exist in
TYPE:
|
account_type
|
Explicit auth-type override.
TYPE:
|
no_browser
|
For oauth_browser, print the authorize URL instead
of launching the browser. Combined with a non-browser
TYPE:
|
secret_stdin
|
For service_account, read the secret from stdin.
Combined with a non-SA
TYPE:
|
token_env
|
For oauth_token, env-var name carrying the bearer.
Defaults to
TYPE:
|
service_account
|
When
TYPE:
|
project_picker
|
Callable invoked with
TYPE:
|
progress
|
Optional CM factory wrapped around the
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AccountSummary
|
class: |
AccountSummary
|
account, with |
AccountSummary
|
populated from the |
| RAISES | DESCRIPTION |
|---|---|
InvalidArgumentError
|
Mutually-incompatible flag combinations
( |
ConfigError
|
Project not visible (E-6), region mismatch (E-2 / E-3), type mismatch (E-4), missing required env (cred collection), or non-interactive context with no project / org default (E-8 / E-9). |
AccountExistsError
|
Derived account name collides with an
existing account (browser flow); pass |
ProjectNotFoundError
|
Explicit |
OAuthError
|
PKCE failure or all-region probe failure
(raised as :class: |
RegionProbeNetworkError
|
All probe attempts failed at the
network layer (subclass of :class: |
Example
# Browser login, single project, derived name from /me org
result = login_unified()
# AccountSummary(name="acme-corp", type="oauth_browser", ...)
# Service account from env, region auto-detected
os.environ["MP_USERNAME"] = "svc"
os.environ["MP_SECRET"] = "..."
result = login_unified() # detects SA, probes region
# Re-login: refresh tokens for an existing account
result = login_unified(name="acme-corp")
Source code in src/mixpanel_headless/accounts.py
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 | |
logout
¶
Remove the on-disk OAuth tokens for an oauth_browser account.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Account name.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
Account not found. |
Source code in src/mixpanel_headless/accounts.py
token
¶
Return the current bearer token for an OAuth account.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Account name;
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str | None
|
For |
str | None
|
For |
str | None
|
via the resolver if unavailable). |
str | None
|
For |
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
Account not found. |
OAuthError
|
OAuth token cannot be resolved (missing tokens, missing env var, etc.). |
Source code in src/mixpanel_headless/accounts.py
export_bridge
¶
export_bridge(
*,
to: Path,
account: str | None = None,
project: str | None = None,
workspace: int | None = None,
) -> Path
Export the named (or active) account as a v2 bridge file.
Resolves the account, attaches any [settings].custom_header as
bridge.headers (B5 — header attaches in memory at resolution time
for the consumer), and writes a 0o600 file at to via
:func:bridge.export_bridge.
| PARAMETER | DESCRIPTION |
|---|---|
to
|
Destination path for the bridge file.
TYPE:
|
account
|
Account to export;
TYPE:
|
project
|
Optional pinned project ID.
TYPE:
|
workspace
|
Optional pinned workspace ID.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Path
|
The path that was written (same as |
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
Account not found, no active account, or
|
OAuthError
|
|
Source code in src/mixpanel_headless/accounts.py
remove_bridge
¶
Remove the v2 bridge file at at (or the default path).
| PARAMETER | DESCRIPTION |
|---|---|
at
|
Bridge file path;
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
|
Source code in src/mixpanel_headless/accounts.py
Frictionless login (login_unified)¶
Composes auth-type detection, region resolution, /me lookup, project picker, and account-name derivation into one call. Backs the CLI's mp login command.
import mixpanel_headless as mp
# Browser PKCE — derives region, name, project from /me.
summary = mp.accounts.login_unified()
print(summary.user_email, summary.project_id, summary.project_name)
# Service account from env, region auto-probed (us → eu → in):
import os
os.environ["MP_USERNAME"] = "sa_xxx"
os.environ["MP_SECRET"] = "..."
summary = mp.accounts.login_unified()
# Re-login: refresh tokens for an existing account.
summary = mp.accounts.login_unified(name="acme-corp")
# Multi-project — supply a picker callback for non-CLI contexts.
def picker(me, sorted_projects):
"""Return the project_id you want to bind."""
return sorted_projects[0][0]
summary = mp.accounts.login_unified(project_picker=picker)
Auth-type detection ladder (priority order):
- Explicit
account_type=(or the CLI's--service-account/--token-env). MP_USERNAME+MP_SECRETset →service_account.MP_OAUTH_TOKENset →oauth_token.- Otherwise →
oauth_browser(PKCE).
Region behavior is auth-type-specific. service_account and oauth_token paths probe us → eu → in against /me when region= is not passed, returning the first 200. oauth_browser commits to the supplied region (or defaults to "us") before the PKCE redirect, then cross-checks the picked project's domain after the callback. EU and India browser users must pass region="eu" or region="in" explicitly.
Raises RegionProbeError / RegionProbeNetworkError if no region accepts the credential (SA / token paths only), InvalidArgumentError for mutually-incompatible flag combinations, ProjectNotFoundError for an explicit project= not visible to /me, and AccountExistsError when the derived name collides on the browser path. See Exceptions for the full set.
mp.session¶
Read and write the persisted [active] block.
mixpanel_headless.session
¶
Public mp.session namespace.
Thin wrapper around :class:~mixpanel_headless._internal.config.ConfigManager
exposing the persisted [active] session and per-axis updates.
Note: this module shadows the :class:Session value type. Public
callers access via import mixpanel_headless; mp.session.show() (module)
or import mixpanel_headless; mp.Session(...) (the type).
Reference: specs/042-auth-architecture-redesign/contracts/python-api.md §7.
show
¶
Return the persisted [active] block.
| RETURNS | DESCRIPTION |
|---|---|
ActiveSession
|
|
ActiveSession
|
None). Project lives on the active account as |
ActiveSession
|
|
Source code in src/mixpanel_headless/session.py
use
¶
use(
*,
account: str | None = None,
project: str | None = None,
workspace: int | None = None,
target: str | None = None,
) -> None
Update one or more axes in the persisted config.
account= and workspace= are written to [active].
project= is written to the active account's default_project
(project lives on the account, not in [active]). target= is
mutually exclusive with the per-axis kwargs and applies all three
axes atomically (writing project to the target account's
default_project).
All updates land in a single apply_session transaction so the
on-disk state never reflects a partial swap (e.g., new account but
stale project).
| PARAMETER | DESCRIPTION |
|---|---|
account
|
New active account name.
TYPE:
|
project
|
New project ID (digit string) for the active account.
TYPE:
|
workspace
|
New active workspace ID.
TYPE:
|
target
|
Apply this target's three axes atomically.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
|
ConfigError
|
Referenced account or target not found, or
|
Source code in src/mixpanel_headless/session.py
mp.targets¶
Manage saved (account, project, optional workspace) cursor positions.
mixpanel_headless.targets
¶
Public mp.targets namespace.
Thin wrapper around :class:~mixpanel_headless._internal.config.ConfigManager
exposing target CRUD and activation. Targets are saved
(account, project, workspace?) triples used as named cursor positions:
mp.targets.use("ecom") writes all three axes to [active] in a
single config save.
Reference: specs/042-auth-architecture-redesign/contracts/python-api.md §6.
list
¶
Return all configured targets sorted by name.
| RETURNS | DESCRIPTION |
|---|---|
list[Target]
|
Sorted list of :class: |
add
¶
Add a new target block.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Target name (block key).
TYPE:
|
account
|
Referenced account name (must exist).
TYPE:
|
project
|
Project ID (digit string).
TYPE:
|
workspace
|
Optional workspace ID.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Target
|
The constructed :class: |
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
Duplicate name, missing account, or validation failure. |
Source code in src/mixpanel_headless/targets.py
remove
¶
Remove a target block.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Target to remove.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
Target does not exist. |
use
¶
Apply the target — write all three axes to [active] atomically.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Target to apply.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
Target does not exist OR its referenced account is gone. |
Source code in src/mixpanel_headless/targets.py
show
¶
Return the named :class:Target.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Target name.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Target
|
The Target record. |
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
Target does not exist. |
Result Types¶
Read-only structured results returned from the namespaces above.
AccountSummary¶
mixpanel_headless.AccountSummary
¶
Bases: BaseModel
Read-only summary of a configured account for mp account list.
Fields are derived from the persisted [accounts.NAME] block plus
runtime context (is_active, referenced_by_targets). Status
reflects the most recent mp account test outcome — "untested"
is the default for accounts that have never been tested in this session.
Example
status
class-attribute
instance-attribute
¶
Result of the most recent mp account test (or "untested").
is_active
class-attribute
instance-attribute
¶
True if [active].account == name.
referenced_by_targets
class-attribute
instance-attribute
¶
Names of targets that reference this account.
user_email
class-attribute
instance-attribute
¶
Authenticated user email, populated by login_unified() from /me.
Persisted in the per-account MeCache (not in config.toml), so
it survives across processes once login has run. None when the
account was added via mp account add (no /me round-trip) or
when /me did not return a user_email.
project_id
class-attribute
instance-attribute
¶
Project ID resolved at login time.
Mirror of the persisted default_project for convenience — exposed
on AccountSummary so the mp login success line can render
Logged in as ... → ... · {project_name} without a second
ConfigManager round-trip. None when no default project is set.
project_name
class-attribute
instance-attribute
¶
Human-readable project name from /me for the resolved project.
Populated alongside project_id by login_unified(). None
when no project is configured or the project is not in /me.
AccountTestResult¶
mixpanel_headless.AccountTestResult
¶
Bases: BaseModel
Outcome of mp account test NAME — captures the /me probe.
Never raises — error context is captured in error so the CLI can
print structured failure messages and mp account list can color
accounts as needs_login / needs_token based on the error code.
The ok/error fields are paired by an invariant: ok=True
iff error is None. Constructing the model with both ok=True
and a non-empty error (or ok=False and error=None) raises
:class:pydantic.ValidationError to prevent ambiguous result states
that would force callers to guess the right field to read.
When the underlying failure is a :class:MixpanelHeadlessError,
error_code and error_details carry the structured fields
so downstream callers (the plugin's auth_manager.py, JSON
consumers) can dispatch on the code instead of parsing the
error message string. Both default to None for the
success path and for failures captured from a non-library
exception (network OSError, programming bug, etc.).
user
class-attribute
instance-attribute
¶
Authenticated principal identity, when ok is True.
accessible_project_count
class-attribute
instance-attribute
¶
Number of projects the account can read from /me.
error
class-attribute
instance-attribute
¶
Human-readable failure reason when ok is False.
error_code
class-attribute
instance-attribute
¶
Machine-readable error code (only set when the cause was a MixpanelHeadlessError).
error_details
class-attribute
instance-attribute
¶
Structured details payload from the underlying MixpanelHeadlessError, if any.
OAuthLoginResult¶
mixpanel_headless.OAuthLoginResult
¶
Bases: BaseModel
Outcome of mp.accounts.login(name) — captures the PKCE flow result.
Returned after a successful OAuth browser flow. user is populated
from the immediate /me probe issued after the token exchange so
callers can confirm "you are now logged in as alice@example.com"
without needing a follow-up call.
user
class-attribute
instance-attribute
¶
Authenticated principal identity from the post-login /me probe.
expires_at
class-attribute
instance-attribute
¶
Access-token expiry (UTC) from the token endpoint response.
tokens_path
instance-attribute
¶
Where the tokens were persisted (~/.mp/accounts/{name}/tokens.json).
client_path
instance-attribute
¶
Where the DCR client info was persisted (~/.mp/accounts/{name}/client.json).
Target¶
mixpanel_headless.Target
¶
Bases: BaseModel
A saved (account, project, workspace?) triple persisted in [targets.NAME].
Targets are named cursor positions: mp target use prod writes all
three axes to [active] in a single config save. Workspace is
optional — when omitted, the target resolves to the project's default
workspace at use time (per FR-025 lazy resolution).
account
instance-attribute
¶
Local config name of the referenced account (must exist).
project
instance-attribute
¶
Numeric project ID (Mixpanel's wire format).
workspace
class-attribute
instance-attribute
¶
Optional workspace ID (must be a positive integer when set);
None defers to lazy resolution. Mirrors WorkspaceRef.id's
PositiveInt constraint so bad values fail at construction rather
than corrupting downstream config.
Credential Resolution Chain¶
When constructing a Workspace, each axis is resolved independently in this priority order:
- Environment variables — the resolver reads
MP_USERNAME+MP_SECRET+MP_PROJECT_ID+MP_REGION(service-account quad),MP_OAUTH_TOKEN+MP_PROJECT_ID+MP_REGION(OAuth-token triple),MP_PROJECT_ID(project axis), andMP_WORKSPACE_ID(workspace axis).MP_ACCOUNTis not consumed by the Python resolver — it only feeds the CLI's--account/-aflag via Typer'senvvar=default. - Constructor / CLI param —
Workspace(account="..."),mp -a NAME .... - Saved target —
Workspace(target="ecom"),mp -t ecom .... - Bridge file —
MP_AUTH_FILEor~/.claude/mixpanel/auth.json. - Persisted active session — the
[active]block in~/.mp/config.toml. - Account default —
account.default_projectfor the project axis.
See Configuration → Credential Resolution Chain for examples.
Cowork Bridge (v2)¶
The Cowork bridge is a v2 JSON file that lets a remote VM authenticate against Mixpanel using your host machine's account and tokens. It embeds the full Account, optional OAuth tokens, and optional pinned project/workspace/headers.
from pathlib import Path
import mixpanel_headless as mp
# On the host
mp.accounts.export_bridge(to=Path("~/.claude/mixpanel/auth.json").expanduser())
mp.accounts.remove_bridge()
# CLI equivalents
mp account export-bridge --to ~/.claude/mixpanel/auth.json
mp account remove-bridge
mp session --bridge # show bridge-resolved state
Default search order: MP_AUTH_FILE → ~/.claude/mixpanel/auth.json → ./mixpanel_auth.json.
mixpanel_headless.auth_types.BridgeFile
¶
Bases: BaseModel
Cowork credential bridge file — v2 schema.
Embeds a full :class:~mixpanel_headless._internal.auth.account.Account
record (with secrets inline) plus optional project / workspace pinning
and a custom-headers map.
Example
{
"version": 2,
"account": {"type": "oauth_browser", "name": "personal", "region": "us"},
"tokens": {"access_token": "...", "refresh_token": "...",
"expires_at": "2026-04-22T12:00:00Z",
"token_type": "Bearer", "scope": "read"},
"project": "3713224",
"workspace": 3448413,
"headers": {"X-Mixpanel-Cluster": "internal-1"}
}
version
class-attribute
instance-attribute
¶
Bridge schema version — always 2.
account
instance-attribute
¶
Full Account discriminated-union record (with secrets inline by design).
tokens
class-attribute
instance-attribute
¶
OAuth tokens — required iff account.type == "oauth_browser".
project
class-attribute
instance-attribute
¶
Optional pinned project ID (numeric string).
workspace
class-attribute
instance-attribute
¶
Optional pinned workspace ID.
headers
class-attribute
instance-attribute
¶
Custom HTTP headers attached to outbound requests at resolution time.
mixpanel_headless.auth_types.load_bridge
¶
Load and validate a v2 bridge file from disk.
Resolves the path in this order:
- Argument
path(if not None). $MP_AUTH_FILEenv var (if set).- Default search paths (
~/.claude/mixpanel/auth.json, then<cwd>/mixpanel_auth.json) — first existing file wins.
| PARAMETER | DESCRIPTION |
|---|---|
path
|
Optional explicit bridge path.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
BridgeFile | None
|
The parsed :class: |
BridgeFile | None
|
path exists. |
| RAISES | DESCRIPTION |
|---|---|
ConfigError
|
If a candidate file exists but is malformed or fails schema validation. |
Source code in src/mixpanel_headless/_internal/auth/bridge.py
OAuth Token Plumbing¶
Low-level types for OAuth token handling. Most users never touch these directly — mp.accounts.login(name) drives the full flow and OnDiskTokenResolver materializes refreshed tokens automatically.
OAuthTokens¶
mixpanel_headless.auth_types.OAuthTokens
¶
Bases: BaseModel
Immutable OAuth 2.0 token set with expiry tracking.
Stores access and optional refresh tokens along with metadata
from the token response. The is_expired method includes a
30-second safety buffer to avoid using tokens that are about to expire.
| ATTRIBUTE | DESCRIPTION |
|---|---|
access_token |
The OAuth access token (redacted in output).
TYPE:
|
refresh_token |
The OAuth refresh token, if provided (redacted in output).
TYPE:
|
expires_at |
UTC datetime when the access token expires.
TYPE:
|
scope |
Space-separated list of granted scopes.
TYPE:
|
token_type |
Token type, typically
TYPE:
|
access_token
instance-attribute
¶
The OAuth access token (redacted in output).
refresh_token
class-attribute
instance-attribute
¶
The OAuth refresh token, if provided (redacted in output).
expires_at
instance-attribute
¶
UTC datetime when the access token expires.
Must be timezone-aware. Naive datetimes are rejected at validation
time so a downstream consumer can never accidentally compare against
an aware datetime.now(timezone.utc) and silently fall through
the expiry check (Fix 25).
is_expired
¶
Check whether the access token is expired or about to expire.
Uses a 30-second safety buffer to avoid sending tokens that are about to expire during in-flight requests.
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if the token is expired or will expire within 30 seconds. |
Example
Source code in src/mixpanel_headless/_internal/auth/token.py
from_token_response
classmethod
¶
Create an OAuthTokens instance from a raw token endpoint response.
Computes expires_at by adding the expires_in value (in seconds)
to the current UTC time.
| PARAMETER | DESCRIPTION |
|---|---|
data
|
Raw JSON response from the token endpoint. Must contain
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
OAuthTokens
|
A new frozen OAuthTokens instance. |
| RAISES | DESCRIPTION |
|---|---|
KeyError
|
If required keys are missing from |
ValueError
|
If |
Example
Source code in src/mixpanel_headless/_internal/auth/token.py
OAuthClientInfo¶
mixpanel_headless.auth_types.OAuthClientInfo
¶
Bases: BaseModel
Immutable OAuth client registration metadata.
Stores client information from Dynamic Client Registration (RFC 7591) for reuse across sessions without re-registering.
| ATTRIBUTE | DESCRIPTION |
|---|---|
client_id |
The OAuth client identifier.
TYPE:
|
region |
Mixpanel data residency region (
TYPE:
|
redirect_uri |
The redirect URI registered with the authorization server.
TYPE:
|
scope |
Space-separated list of requested scopes.
TYPE:
|
created_at |
UTC datetime when the client was registered.
TYPE:
|
redirect_uri
instance-attribute
¶
The redirect URI registered with the authorization server.
TokenResolver Protocol¶
mixpanel_headless.auth_types.TokenResolver
¶
Bases: Protocol
Protocol for producing bearer tokens for OAuth accounts.
Implementations decide how to fetch (and refresh) tokens for the two
OAuth account variants. Concrete implementations live in
:mod:mixpanel_headless._internal.auth.token_resolver.
get_browser_token
¶
Return a fresh access token for an :class:OAuthBrowserAccount.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Account name (used to locate persisted tokens on disk).
TYPE:
|
region
|
Mixpanel region (used by some implementations).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The current access token (no |
Source code in src/mixpanel_headless/_internal/auth/account.py
get_static_token
¶
Return the static bearer for an :class:OAuthTokenAccount.
| PARAMETER | DESCRIPTION |
|---|---|
account
|
The account whose
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The bearer token (no |
Source code in src/mixpanel_headless/_internal/auth/account.py
OnDiskTokenResolver¶
mixpanel_headless.auth_types.OnDiskTokenResolver
¶
Bases: TokenResolver
Default resolver: tokens live on disk per account.
Reads OAuth browser tokens from ~/.mp/accounts/{name}/tokens.json
written by :class:OAuthFlow. Reads static tokens from either the
inline token field on the account or the environment variable
named in token_env.
The resolver is intentionally I/O-light: the only side effects are
reading files that already exist and (for expired browser tokens)
refreshing via :meth:_refresh_and_persist, which delegates to
:class:OAuthFlow.refresh_tokens and rewrites
~/.mp/accounts/{name}/tokens.json atomically via
atomic_write_bytes. All failures surface as :class:OAuthError
so callers can give actionable error messages.
get_browser_token
¶
Return a fresh access token for an :class:OAuthBrowserAccount.
Reads ~/.mp/accounts/{name}/tokens.json, checks the recorded
expires_at (with a 30s safety buffer), and returns the token
if not expired. If expired, refreshes via
:meth:_refresh_and_persist; raises
:class:OAuthError(code="OAUTH_REFRESH_ERROR") if no refresh
token is recorded.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Account name (used to locate the tokens file).
TYPE:
|
region
|
Mixpanel region (kept for parity with the protocol; used by some refresh paths).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The current access token (no |
| RAISES | DESCRIPTION |
|---|---|
OAuthError
|
If the tokens file is missing, malformed, expired without a refresh token, or refresh fails. |
Source code in src/mixpanel_headless/_internal/auth/token_resolver.py
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | |
get_static_token
¶
Return the static bearer for an :class:OAuthTokenAccount.
Resolves the bearer from the inline token field if present;
otherwise reads the environment variable named in token_env.
| PARAMETER | DESCRIPTION |
|---|---|
account
|
The account whose
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The bearer token (no |
| RAISES | DESCRIPTION |
|---|---|
OAuthError
|
If |