PrefectHQ/fastmcp · error · ValueError

tenant_name should be the short name without the .onmicrosof

Error message

tenant_name should be the short name without the .onmicrosoft.com suffix (e.g. 'mytenant'), got {tenant_name!r}

What it means

AzureProvider.from_b2c builds B2C endpoints from tenant_name as https://{tenant_name}.b2clogin.com and the issuer as https://{tenant_name}.onmicrosoft.com/{client_id}. If you pass a tenant_name that already contains '.onmicrosoft.com', the constructed URLs would be malformed (double suffix), so the classmethod rejects it with ValueError.

Source

Thrown at fastmcp_slim/fastmcp/server/auth/providers/azure.py:343

                (e.g. `"mytenant"`).
            policy_name: User-flow or custom-policy name
                (e.g. `"B2C_1_susi"`).
            client_id: Application (client) ID from the B2C app registration.
            client_secret: Client secret from the B2C app registration.
            required_scopes: Custom API scope names without prefix
                (e.g. `["mcp-access"]`).
            base_url: Public base URL of this server.
            custom_domain: Custom domain for the B2C authority
                (e.g. `"auth.mycompany.com"`). Defaults to
                `{tenant_name}.b2clogin.com`.
            identifier_uri: Application ID URI. Defaults to
                `https://{tenant_name}.onmicrosoft.com/{client_id}`.
            token_issuer: Expected `iss` claim. `None` (default) disables
                issuer validation.
            **kwargs: Forwarded to `AzureProvider.__init__`.
        """
        if ".onmicrosoft.com" in tenant_name:
            raise ValueError(
                f"tenant_name should be the short name without the "
                f".onmicrosoft.com suffix (e.g. 'mytenant'), got {tenant_name!r}"
            )

        if custom_domain is not None:
            custom_domain = (
                custom_domain.removeprefix("https://")
                .removeprefix("http://")
                .rstrip("/")
            )

        authority = custom_domain or f"{tenant_name}.b2clogin.com"
        tenant_path = f"{tenant_name}.onmicrosoft.com/{policy_name}"
        uri = identifier_uri or f"https://{tenant_name}.onmicrosoft.com/{client_id}"

        provider = cls(
            client_id=client_id,
            client_secret=client_secret,

View on GitHub (pinned to 1f02114297)

Solutions

  1. Strip the .onmicrosoft.com suffix: pass 'mytenant' instead of 'mytenant.onmicrosoft.com'.
  2. If you have the full domain, split it: tenant_name = domain.split('.onmicrosoft.com')[0].
  3. Use a custom_domain argument if your B2C tenant uses a custom login domain.

Example fix

// before
AzureProvider.from_b2c(tenant_name="mytenant.onmicrosoft.com", client_id=cid)
// after
AzureProvider.from_b2c(tenant_name="mytenant", client_id=cid)
Defensive patterns

Strategy: validation

Validate before calling

def normalize_b2c_tenant(name: str) -> str:
    if ".onmicrosoft.com" in name:
        raise ValueError("Pass the short tenant name without .onmicrosoft.com")
    return name

Type guard

def is_short_tenant_name(name: str) -> bool:
    return bool(name) and ".onmicrosoft.com" not in name and "/" not in name

Try / catch

try:
    provider = AzureProvider.from_b2c(tenant_name=tenant, client_id=cid)
except ValueError as e:
    if ".onmicrosoft.com" in str(e):
        provider = AzureProvider.from_b2c(tenant_name=tenant.split(".")[0], client_id=cid)
    else:
        raise

Prevention

When it happens

Trigger: Calling AzureProvider.from_b2c(tenant_name='mytenant.onmicrosoft.com', ...) — the check `'.onmicrosoft.com' in tenant_name` fires for any such value.

Common situations: Copy-pasting the full tenant domain from the Azure portal or from a token's issuer claim instead of the short B2C tenant name; configuring from environment variables that hold the full domain.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/5a84023c3b2711ae. Report an issue: GitHub.