[Bug] macOS broker prompts twice for Keychain access, Always Allow doesn't apply to both
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 25/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Tranquilla
- Stack tecnologico
- macos, python
- Ambito
- authentication, security
Direzione di ricerca
The report points to Common Core’s MSIDMacKeychainTokenCache.m and MSIDMacACLKeychainAccessor.m, and asks about PyMsalRuntime’s unsigned-client flow. Start by tracing how one broker response is written to the shared and non-shared Keychain items, then check whether the Python repository exposes that flow. Done means establishing a supported way to avoid duplicate authorization prompts while preserving the shared/non-shared credential boundary.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Describe the bug
On macOS, one broker-backed MSAL operation can (frequently) display two consecutive Keychain password dialogs. Choosing Always Allow in the first dialog does not prevent the second dialog. After choosing Always Allow in both dialogs, later requests stop prompting until the interpreter identity or Keychain state changes.
I had copilot confirm that my app makes one msal.broker._signin_silently() call and that MSAL makes one native pymsalruntime.signin_silently() call. The dialogs therefore arise within one native broker operation rather than from duplicate application authentication. It feels wrong to have to type my password twice for a single operation.
To reproduce
Prerequisites:
- macOS with Company Portal and broker support configured.
- A public client registration configured for the macOS broker.
- An account already available to the broker.
- An ad-hoc-signed Python executable that is not already trusted by the relevant login-Keychain items.
import msal
CLIENT_ID = "<public-client-id>"
AUTHORITY = "https://login.microsoftonline.com/<tenant>"
SCOPES = ["<scope>"]
app = msal.PublicClientApplication(
client_id=CLIENT_ID,
authority=AUTHORITY,
enable_broker_on_mac=True,
)
# With prompt omitted, the broker path first attempts one silent sign-in.
result = app.acquire_token_interactive(scopes=SCOPES)
print(result.get("error") or "Token acquired")
Run the script with the ad-hoc-signed interpreter. When its executable has not previously been authorized for the existing MSAL Keychain cache, two Keychain dialogs will appear during the single silent broker operation.
Expected behavior
A single broker operation should not require two indistinguishable Keychain authorization grants. Ideally, an unsigned runtime-like broker client would rely on broker-owned persistent caching and use only process-local application caching. If persistent application-side Keychain caching is required, the UX should avoid or clearly explain multiple independent grants without weakening the shared/non-shared credential boundary.
What you see instead
- macOS requests the login-Keychain password.
- Always Allow is selected.
- A second, apparently identical Keychain password dialog immediately appears.
- Always Allow is selected again.
- Subsequent runs remain silent for a period of time.
The MSAL Python version you are using
msal==1.38.0
pymsalruntime==0.20.6
MSAL Python 1.38.0 already contains the unsigned-app redirect URI change from #907.
Environment
- macOS 26.6.2
- Apple Silicon (
arm64) - Company Portal 5.2606.0
- CPython 3.11.12 installed by uv
- Python signature: ad-hoc/linker-signed
TeamIdentifier=not set
Investigation
Non-PII native logging showed:
- The runtime continuing through the unsigned-app runtime flow.
- Shared Keychain-group operations failing with
-34018(errSecMissingEntitlement), as expected for an ad-hoc-signed Python executable without the shared Keychain entitlement. - A fallback to the ACL-based login-Keychain implementation.
- Multiple successful reads and updates through the macOS ACL Keychain accessor during the one silent sign-in.
The Common Core implementation appears to explain why two grants are needed:
MSIDMacKeychainTokenCache.mstores two distinct generic-password items:- A shared blob containing refresh tokens and accounts.
- A non-shared blob containing access tokens, ID tokens, app metadata, and account metadata.
- Both use the service/ACL label
Microsoft Credentials, but they have different Keychain primary keys and independent ACLs. MSIDMacACLKeychainAccessor.mcreates a trusted-application reference for the current executable and reads each item withSecItemCopyMatching.
This is consistent with the observed behavior: Always Allow updates authorization for one Keychain item, but the other item still needs a separate grant even though the dialogs look the same. A changed Python installation path or executable identity can require new grants.
Upstream question
For unsigned runtime-like clients using the macOS broker, can PyMsalRuntime/Common Core avoid writing the broker response to the legacy ACL-based login-Keychain token cache and instead rely on broker persistence plus an in-memory process cache?
If the local cache is required for account discovery or other semantics, is there another way to avoid two separate user authorization dialogs while retaining the intentional shared/non-shared security boundary?
No tenant IDs, client IDs, account identifiers, correlation IDs, or token material are included in this report.
- Lingua principale
- Python
- Stelle
- 971
- Fork
- 223
- Merge medio
- 13h 48m
- PR unite (30g)
- 2
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di AzureAD/microsoft-authentication-library-for-python
-
needs attention untriaged
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
AzureAD/microsoft-authentication-library-for-python#973 · 1 commento ·
-
AzureSDK bug P1
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
-
http_client docstring does not say that timeout, verify and proxies only configure the default sessionForse già presa @HardMax71 l’ha presa 40 giorni fa. Aperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 25/100
-
[Bug] The built-in retry never retries the token POST: HTTPAdapter(max_retries=1) keeps urllib3's default allowed_methodsForse già presa @HardMax71 l’ha presa 46 giorni fa. Apertabug untriaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 35/100
AzureAD/microsoft-authentication-library-for-python#957 · 3 commenti ·
-
[Bug] Interactive auth callback hangs forever when an idle connection reaches AuthCodeReceiver firstForse già presa @Thanatos9404 l’ha presa 5 giorni fa. Apertabug public-client
Difficoltà 4/5 1-2 giorni Idoneità per principianti 48/100
AzureAD/microsoft-authentication-library-for-python#950 · 2 commenti · 3 reazioni ·
Tutte le issue di AzureAD/microsoft-authentication-library-for-python
Issue simili
-
idxmax/idxmin raise ValueError when a single partition is all-NAForse già presa @Jason10191019999 l’ha presa oggi. Apertaneeds triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 3 giorni
-
Old versions of datamodelsApertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
-
[BUG]: Windows GUI package of v1.17.0-rc3 has no GTK DLLsForse già presa @andrut-ds l’ha presa oggi. Apertabug CI/CD Pactus-GUI Windows
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
pactus-project/pactus#2428 ·
I maintainer di solito rispondono entro 1 giorno
-
DiskDataset.reshard() can hang with a zero or negative shard sizeForse già presa @Programmer-Develops l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 19 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
GNS3/gns3-server#3017 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno