Skip to content

Derive ARM auth scopes from endpoint URL#928

Draft
cataggar wants to merge 1 commit intoAzure:mainfrom
cataggar:fix/arm-auth-scope
Draft

Derive ARM auth scopes from endpoint URL#928
cataggar wants to merge 1 commit intoAzure:mainfrom
cataggar:fix/arm-auth-scope

Conversation

@cataggar
Copy link
Copy Markdown
Member

@cataggar cataggar commented Apr 4, 2026

Problem

ARM TypeSpec specs declare OAuth2 with relative scopes like user_impersonation. The emitter passes this bare scope verbatim to BearerTokenAuthorizationPolicy::new(). When Azure CLI or other identity libraries try to acquire a token for just user_impersonation, it resolves to Microsoft Graph (00000003-0000-0000-c000-000000000000) instead of Azure Management, causing authentication failures:

AADSTS65002: Consent between first party application '04b07795-...'
and first party resource '00000003-...' must be configured via preauthorization

Fix

When scopes are relative (not absolute URLs), generate code that derives the scope from the endpoint origin at runtime using the standard Azure SDK pattern: {endpoint_origin}/.default.

Before (broken):

BearerTokenAuthorizationPolicy::new(credential, vec!["user_impersonation"])

After (fixed):

BearerTokenAuthorizationPolicy::new(
    credential,
    vec![format!("{}/.default", endpoint.origin().ascii_serialization())],
)

Absolute scopes (e.g. https://vault.azure.net/.default used by data-plane services) are still emitted as static strings.

This is consistent with other Azure SDK languages (Python uses f"{base_url}/.default", Go uses cloud.Services[ResourceManager].Audience + "/.default").

Validation

ARM TypeSpec specs declare OAuth2 with relative scopes like
'user_impersonation'. Passing this bare scope to the Azure
identity libraries fails because it resolves to the wrong
resource (Microsoft Graph instead of Azure Management).

When scopes are relative (not absolute URLs), generate code
that derives the scope from the endpoint origin at runtime
using the '{endpoint_origin}/.default' pattern. This is
consistent with other Azure SDK languages (Python, Go) and
correctly handles sovereign clouds.

Absolute scopes (e.g. 'https://vault.azure.net/.default')
are still emitted as static strings.
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