Search code examples
c#azure-active-directorymicrosoft-fabric

Generating token for Fabric Rest api using client secret


I am working as a POC where I have to connect to Fabric Rest API from c# and I want to create Items. I am able to create items as per the instructions provided on https://learn.microsoft.com/en-us/rest/api/fabric/articles/get-started/fabric-api-quickstart. The challenge I am facing is with token creation. As per the instructions provided on this page, I am getting a login page and after successful authentication, the token is generated. I am going to use the token creation call inside api but I don't have a provision to authenticate. I need some guidance on how to generate the token using client secret if possible. I am currently using the code below:

using Microsoft.Identity.Client;
#region parameters section 
string ClientId = "clientID";
string Authority = "https://login.microsoftonline.com/organizations";
string RedirectURI = "http://localhost";
#endregion

#region Acquire a token for Fabric APIs 
// In this sample we acquire a token for Fabric service with the scopes  
// Workspace.ReadWrite.All and Item.ReadWrite.All 
string[] scopes = new string[] { "https://api.fabric.microsoft.com/Workspace.ReadWrite.All https://api.fabric.microsoft.com/Item.ReadWrite.All" };

PublicClientApplicationBuilder PublicClientAppBuilder =
        PublicClientApplicationBuilder.Create(ClientId)
        .WithAuthority(Authority)
        .WithRedirectUri(RedirectURI);

IPublicClientApplication PublicClientApplication = PublicClientAppBuilder.Build();

AuthenticationResult result = await PublicClientApplication.AcquireTokenInteractive(scopes)
        .ExecuteAsync()
        .ConfigureAwait(false);

Console.WriteLine(result.AccessToken);
#endregion

I have created a new app registration in Azure active directory and added api permission for Power Bi and azure storage. I also provided the admin consent to the newly added permission. I created a client secret and tried to create a token in postman. The token is created but when using this token, its gives me a bad request. When using the token generated from the c# code, its working fine.


Solution

  • Initially, I registered one Entra ID application and created one client secret in it:

    enter image description here

    You need to add above service principal to Fabric workspaces giving at least Contributor role like this:

    enter image description here

    Before generating tokens, make sure to allow access to service principals to use Fabric APIs by enabling below option in Admin Portal:

    enter image description here

    Now, you can generate access token using client credentials flow via Postman with below parameters:

    POST https://login.microsoftonline.com/tenantId/oauth2/v2.0/token
    grant_type:client_credentials
    client_id:appId
    client_secret:secret
    scope: https://api.fabric.microsoft.com/.default
    

    Response:

    enter image description here

    When I used this token to list workspaces by calling Fabric API, I got the response successfully like this:

    GET https://api.fabric.microsoft.com/v1/workspaces/
    

    Response:

    enter image description here

    To get the same response in c# by generating token with client credentials flow, you can make use of below sample code:

    #region
    using Microsoft.Identity.Client;
    using System.Net.Http.Headers;
    
    string ClientId = "appId";
    string ClientSecret = "secret"; 
    string Authority = "https://login.microsoftonline.com/tenantId";
    #endregion
    
    #region 
    string[] scopes = new string[] { "https://api.fabric.microsoft.com/.default" };
    
    ConfidentialClientApplicationBuilder confidentialClientAppBuilder =
        ConfidentialClientApplicationBuilder.Create(ClientId)
        .WithClientSecret(ClientSecret)
        .WithAuthority(Authority);
    
    IConfidentialClientApplication confidentialClientApplication = confidentialClientAppBuilder.Build();
    
    AuthenticationResult result = await confidentialClientApplication.AcquireTokenForClient(scopes)
        .ExecuteAsync()
        .ConfigureAwait(false);
    
    Console.WriteLine(result.AccessToken);
    Console.WriteLine();
    #endregion
    
    
    // Create client 
    HttpClient client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
    string baseUrl = "https://api.fabric.microsoft.com/v1/";
    client.BaseAddress = new Uri(baseUrl);
    
    // Call list workspaces API 
    HttpResponseMessage response = await client.GetAsync("workspaces");
    string responseBody = await response.Content.ReadAsStringAsync();
    Console.WriteLine(responseBody);
    

    Response:

    enter image description here

    UPDATE:

    When I tried to get the item from workspace where service principal does not have at least Contributor access, I too got same error:

    GET https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/items/{itemId}
    

    Response:

    enter image description here

    To resolve the error, make sure to grant at least Contributor access to the service principal under the workspace in which you are getting error:

    enter image description here

    When I ran the call after granting access, I'm able to fetch the item successfully by invoking this API:

    GET https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/items/{itemId}
    

    Response:

    enter image description here

    But for some other operations like creating items in workspace, etc... service principal authentication (client credentials flow) is not supported.

    When I tried to create item under workspace with service principal token, I got error saying "The operation is not supported for the principal type" like this:

    POST https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/items/
    {
        "displayName": "Item 1",
        "type": "Lakehouse" 
    }
    

    Response:

    enter image description here

    Reference: Microsoft Fabric REST APIs | Microsoft