{"record":{"id":"4dafaafc28c61651","repo":"hashicorp/terraform","slug":"unable-to-build-authorizer-for-storage-api-v","errorCode":null,"errorMessage":"unable to build authorizer for Storage API: %+v","messagePattern":"unable to build authorizer for Storage API: %\\+v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/azure/api_client.go","lineNumber":64,"sourceCode":"\t\tenvironment:        config.AuthConfig.Environment,\n\t\tstorageAccountName: config.StorageAccountName,\n\t}\n\n\tvar armAuthRequired bool\n\tswitch {\n\tcase config.AccessKey != \"\":\n\t\tclient.accessKey = config.AccessKey\n\tcase config.SasToken != \"\":\n\t\tsasToken := config.SasToken\n\t\tif strings.TrimSpace(sasToken) == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"sasToken cannot be empty\")\n\t\t}\n\t\tclient.sasToken = strings.TrimPrefix(sasToken, \"?\")\n\tcase config.UseAzureADAuthentication:\n\t\tvar err error\n\t\tclient.azureAdStorageAuth, err = auth.NewAuthorizerFromCredentials(ctx, *config.AuthConfig, config.AuthConfig.Environment.Storage)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to build authorizer for Storage API: %+v\", err)\n\t\t}\n\tdefault:\n\t\t// AAD authentication (ARM scope) is required only when no auth method is specified, which falls back to listing the access key via ARM API.\n\t\tarmAuthRequired = true\n\t}\n\n\t// If `config.LookupBlobEndpoint` is true, we need to authenticate with ARM to lookup the blob endpoint\n\tif config.LookupBlobEndpoint {\n\t\tarmAuthRequired = true\n\t}\n\n\tif armAuthRequired {\n\t\tresourceManagerAuth, err := auth.NewAuthorizerFromCredentials(ctx, *config.AuthConfig, config.AuthConfig.Environment.ResourceManager)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to build authorizer for Resource Manager API: %+v\", err)\n\t\t}\n\n\t\t// When using Azure CLI to auth, the user can leave the \"subscription_id\" unspecified. In this case the subscription id is inferred from","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/azure/api_client.go#L46-L82","documentation":"Thrown by Azure buildClient in the use_azuread_authentication=true branch when auth.NewAuthorizerFromCredentials cannot construct an Azure AD authorizer for the Storage data-plane scope. The %+v expands the underlying auth error (missing field, bad endpoint, wrong tenant, etc.).","triggerScenarios":"config.UseAzureADAuthentication is true and auth.NewAuthorizerFromCredentials(ctx, *config.AuthConfig, config.AuthConfig.Environment.Storage) returns err. Typical root causes: client_id/tenant_id/client_secret missing or malformed, the named Environment does not define a Storage endpoint, or the credentials do not match a real app registration.","commonSituations":"Service principal misconfigured in the backend block or via ARM_* env vars (wrong tenant, expired client_secret, swapped client_id and object_id), using a custom cloud name that has no Storage endpoint, or AAD workarounds that omit required fields.","solutions":["Read the wrapped %+v error first; it usually names the exact missing/invalid field.","Confirm client_id, tenant_id (or tenant_id for OIDC), and client_secret / client_certificate_path / use_oidc are all set and consistent in the azurerm backend block or ARM_* env vars.","Verify the environment name resolves a Storage endpoint (for custom clouds, define environment metadata with a Storage resource manager).","Rotate an expired client secret and update both the app registration and the backend config."],"exampleFix":"# before: missing tenant_id / wrong scope\nexport ARM_CLIENT_ID=00000000-0000-0000-0000-000000000000\nexport ARM_USE_AAD=true\n# after\nexport ARM_CLIENT_ID=00000000-0000-0000-0000-000000000000\nexport ARM_CLIENT_SECRET=...\nexport ARM_TENANT_ID=11111111-1111-1111-1111-111111111111\nexport ARM_SUBSCRIPTION_ID=22222222-2222-2222-2222-222222222222\nexport ARM_USE_AAD=true","handlingStrategy":"validation","validationCode":"func validateAADCreds(c BackendConfig) error {\n    if c.AuthConfig == nil { return fmt.Errorf(\"missing auth config\") }\n    if c.AuthConfig.ClientID == \"\" { return fmt.Errorf(\"client_id missing for AAD auth\") }\n    if c.AuthConfig.TenantID == \"\" { return fmt.Errorf(\"tenant_id missing for AAD auth\") }\n    if !c.AuthConfig.UseOIDC && c.AuthConfig.ClientSecret == \"\" && c.AuthConfig.ClientCertificatePath == \"\" {\n        return fmt.Errorf(\"client_secret or client_certificate_path required for non-OIDC AAD auth\")\n    }\n    return nil\n}","typeGuard":"null","tryCatchPattern":"client, err := azure.NewClient(ctx, cfg)\nif err != nil && strings.Contains(err.Error(), \"unable to build authorizer for Storage API\") {\n    // surface the wrapped %+v cause and point the user at client_id/tenant_id/secret\n}","preventionTips":["Keep the SP app registration's client_id, tenant_id, and secret in sync across config and CI.","Rotate expiring client secrets before they lapse and update both the registration and the backend config.","For custom clouds, verify the environment metadata defines a Storage endpoint before using AAD auth."],"tags":["azure","backend","authentication","aad","configuration","service-principal"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}