OAUTH2 In Microsoft Fabric
In my previous article, 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.
To get started we need to register the application at https://entra.microsoft.com
Once logged in, navigate to Applications >>App registrations >> New registration
and register a new application
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.
also Client Secrets
will be required.
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.
The Code
Declare a bunch of variables
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
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
string accesstoken = await GetOAuthToken(tenantId, clientId, clientSecret);
Create a method to fetch details of all workspaces on the tenant
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.
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
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
private static string endpoint = $"https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/lakehouses";
The complete code
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 preferAzure.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 !!!
Subscribe to my newsletter
Read articles from Sachin Nandanwar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by