Skip to content

Fix Microsoft Graph filesystem auth by defaulting OAuth2 scope - #70879

Open
haseebmalik18 wants to merge 1 commit into
apache:mainfrom
haseebmalik18:fix-msgraph-fs-scope-fallback
Open

Fix Microsoft Graph filesystem auth by defaulting OAuth2 scope#70879
haseebmalik18 wants to merge 1 commit into
apache:mainfrom
haseebmalik18:fix-msgraph-fs-scope-fallback

Conversation

@haseebmalik18

Copy link
Copy Markdown
Contributor

Fixes the Microsoft Graph filesystem failing to authenticate when the connection is set up through the UI.

The connection form only exposes a "Scopes" field, but get_fs() hands MSGDriveFS a fully built oauth2_client_params dict. That makes the library skip its own scope default, so authlib ends up with no scope and the connection fails. This falls back to the connection's scopes value, then to the Graph default, so a UI-configured connection works without hand-adding a scope key to extras.

closes: #70822


@potiuk

potiuk commented Aug 1, 2026

Copy link
Copy Markdown
Member

Good diagnosis — the connection form does expose a Scopes field (hooks/msgraph.py:258, defaulting to DEFAULT_SCOPE), but get_fs built oauth2_client_params without a scope key, so MSGDriveFS skipped its own default and authlib was left with nothing. A UI-configured connection could not authenticate.

The precedence you chose is right — explicit scope, then the form's scopes, then the Graph default — and parametrizing over all three branches is the right way to pin it.

One thing to fix before this goes in: the two consumers of that same field disagree on how it is delimited.

MSGraphAsyncOperator's hook treats scopes as comma-separated and splits it:

scopes = config.get("scopes", self.scopes)
if isinstance(scopes, str):
    scopes = scopes.split(",")

This change passes the value through verbatim into the OAuth2 scope parameter, which is space-delimited by spec. So a connection configured the way the hook expects — "User.Read,Files.Read" — reaches authlib as the single literal string "User.Read,Files.Read", which is one malformed scope rather than two. Single-scope values work, which is why the current tests pass; they only ever use one value.

That is the same shape as the bug being fixed here: one field, two consumers, different expectations.

Something like this keeps both readings working:

scopes = get_field(conn_id=conn_id, conn_type=conn_type, extras=extras, field_name="scopes")
if isinstance(scopes, str):
    scopes = " ".join(s.strip() for s in scopes.split(",") if s.strip())
oauth2_client_params["scope"] = scopes or DEFAULT_SCOPE

Worth a fourth parametrize case with a comma-separated value so the behaviour is pinned rather than assumed.

Minor, while you're in there: DEFAULT_SCOPE is redefined here as a module constant, but KiotaRequestAdapterHook.DEFAULT_SCOPE already holds the same literal. Importing it would keep the two from drifting apart later.


Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting

@haseebmalik18
haseebmalik18 force-pushed the fix-msgraph-fs-scope-fallback branch from 764a9de to 431b39f Compare August 1, 2026 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

scopes vs scope mismatch in azure provider (msgraphfs vs KiotaRequestAdapter)

2 participants