# OAUTH2 In Microsoft Fabric

In my previous [article](https://www.azureguru.net/service-principal-in-microsoft-fabric), I discussed how to leverage the newly introduced service principal support in Azure. In that article I used `Azure SDK` to create tokens to authenticate through service principal. This made me think if its possible to use custom `OAUTH2` tokens in Microsoft Fabric instead of `Azure SDK` generated tokens through service principal.

So lets find out.

### The Setup

First, ensure that the Service Principal setting is enabled on your Fabric tenant.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1727627543172/4c3bb666-e633-4a84-a081-54700cb6ce01.png align="left")

To get started we need to register the application at [**https://entra.microsoft.com**](https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/quickStartType~/null/sourceType/Microsoft_AAD_IAM/appId/ad53ea30-aa6b-4232-a596-b00f31920145/objectId/1d59f9c6-36a8-43f3-a862-32e7d087ddde/isMSAApp~/false/defaultBlade/Overview/appSignInAudience/AzureADMyOrg/servicePrincipalCreated~/true)

Once logged in, navigate to **Applications &gt;&gt;App registrations &gt;&gt; New registration**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724690897503/35730069-9cfa-438d-b3b5-d15cd01735f7.png?auto=compress,format&format=webp align="left")

and register a new application

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728325248568/3ee958ec-9083-47f8-b724-a1bb754fe167.png align="center")

I have registered the application with name `Fabric OAUTH2`. We would required `Client ID` and `Tenant ID` values to reference in the code from the registered app.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728325131806/89c5a3b5-1198-4063-9b89-41d94c08626e.png align="center")

also `Client Secrets` will be required.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728325764899/4dbb93b2-ba66-4456-ae0b-d9925262920d.png align="center")

Now that the feature is enabled in the next step we would grant access to the registered app to connect to the workspaces. In this case we would assign contributor access for the workspace.

In your Fabric tenant, under the workspace, select `Manage access` and assign `Contributor` access to the application principal that was created in the earlier step.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1727632426801/297e1778-8c77-464a-8c5f-d12611b7d0bb.png align="left")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728339938384/5b88788d-5110-45b3-95a1-0f81275a9c31.png align="left")

### The Code

Declare a bunch of variables

```csharp
 private static string response = "";
 private static string clientId = "Client Id of the Registered App";
 private static string tenantId = "Tenant Id of the Registered App";
 private static string clientSecret = "Client Secret of the Registered App";
 private static string endpoint = $"https://api.fabric.microsoft.com/v1/workspaces";
```

Method to create a `OAUTH2` token. The `uri` used for token generation is `https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token`

```csharp
   private static async Task<string> GetOAuthToken(string tenantId, string clientId, string clientSecret)
   {
       var Endpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";
       var client = new HttpClient();

       var request = new HttpRequestMessage(HttpMethod.Get, Endpoint)
       {
           Content = new FormUrlEncodedContent(new[]
           {
           new KeyValuePair<string, string>("client_id", clientId),
           new KeyValuePair<string, string>("scope", "https://api.fabric.microsoft.com/.default"),
           new KeyValuePair<string, string>("client_secret", clientSecret),
           new KeyValuePair<string, string>("grant_type", "client_credentials")
       })
       };

       HttpResponseMessage response = await client.SendAsync(request);
       response.EnsureSuccessStatusCode();
       var content = await response.Content.ReadAsStringAsync();           
       var tokenResponse = System.Text.Json.JsonDocument.Parse(content);
       string accessToken = tokenResponse.RootElement.GetProperty("access_token").GetString();
       return accessToken;
   }
```

Call to the above method

```csharp
  string accesstoken = await GetOAuthToken(tenantId, clientId, clientSecret);
```

Create a method to fetch details of all workspaces on the tenant

```csharp
  private static async Task<string> ListAllWorkSpaces(string accessToken, string oneLakeContainerUrl)
  {
      var httptclient = new HttpClient();
      httptclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
      HttpResponseMessage response = await httptclient.GetAsync(oneLakeContainerUrl);
      response.EnsureSuccessStatusCode();
      return await response.Content.ReadAsStringAsync();
  }
```

Call to the above method and output the details of the workspaces.

```csharp
 response = await ListAllWorkSpaces(accesstoken, endpoint);
 string prettyJson = JsonSerializer.Serialize(JsonSerializer.Deserialize<object>(response), 
      new JsonSerializerOptions { WriteIndented = true }
  );
```

There is only one workspace on the tenant

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728342914128/8955ccf5-8f08-4843-9f00-ece03e239e22.png align="left")

If we want to fetch the details of all the lakehouses under the workspace, we set the value of the endpoint `uri` to the following

```csharp
  private static string endpoint = $"https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/lakehouses";
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728343345514/f98c480d-742e-416a-af2f-eb6a2d860da7.png align="left")

The complete code

```csharp
using Azure.Identity;
using Azure.Storage.Files.DataLake;
using System.Net.Http.Headers;
using System.Text.Json;

namespace Fabric_OAUTH2
{
    internal class Program
    {
        private static string response = "";
        private static string clientId = "Client Id of the Registered App";
        private static string tenantId = "Tenant Id of the Registered App";
        private static string clientSecret = "Client Secret of the Registered App";
        private static string endpoint = $"https://api.fabric.microsoft.com/v1/workspaces";

        static async Task Main(string[] args)
        {
            string accesstoken = await GetOAuthToken(tenantId, clientId, clientSecret);
            response = await ListAllWorkSpaces(accesstoken, endpoint);
            string prettyJson = JsonSerializer.Serialize(JsonSerializer.Deserialize<object>(response),
            new JsonSerializerOptions { WriteIndented = true });
            Console.WriteLine(prettyJson);
        }

        private static async Task<string> GetOAuthToken(string tenantId, string clientId, string clientSecret)
        {
            var Endpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";
            var client = new HttpClient();

            var request = new HttpRequestMessage(HttpMethod.Get, Endpoint)
            {
                Content = new FormUrlEncodedContent(new[]
                {
         new KeyValuePair<string, string>("client_id", clientId),
         new KeyValuePair<string, string>("scope", "https://api.fabric.microsoft.com/.default"),
         new KeyValuePair<string, string>("client_secret", clientSecret),
         new KeyValuePair<string, string>("grant_type", "client_credentials")
     })
            };

            HttpResponseMessage response = await client.SendAsync(request);
            response.EnsureSuccessStatusCode();
            var content = await response.Content.ReadAsStringAsync();
            var tokenResponse = System.Text.Json.JsonDocument.Parse(content);
            string accessToken = tokenResponse.RootElement.GetProperty("access_token").GetString();
            return accessToken;
        }

        private static async Task<string> ListAllWorkSpaces(string accessToken, string oneLakeContainerUrl)
        {
            var httptclient = new HttpClient();
            httptclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
            HttpResponseMessage response = await httptclient.GetAsync(oneLakeContainerUrl);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsStringAsync();
        }
    }
}
```

### Conclusion

Though I personally would prefer using `Azure.SDK` for token generation for service principal in Fabric, using `OAuth2` as an industry-standard protocol for authorization would ensure that applications can interact securely with Fabric services.

If an web or 3rd party application needs to interact with Fabric services I would prefer using `OAUTH2` and if Azure services need to interact with Fabric I would prefer`Azure.SDK`. As service principal is still a fairly new feature introduced in Fabric, I think it would premature to comment on the pro and cons of the two approaches but again that’s just my personal opinion.  
  
Thanks for reading !!!
