Skip to main content

Command Palette

Search for a command to run...

SAS Tokens in Microsoft Fabric

Updated
5 min read
SAS Tokens in Microsoft Fabric
S
From Synapse Analytics, Power BI, Spark, Microsoft Fabric,ASP.NET Core and recently Agentic AI on .NET I try to explore, learn and share all aspects of Microsoft Data Stack in this blog.

Last month the Fabric team announced the availability of OneLake Shared Access Signatures (SAS) feature for Fabric. You can read the official announcement here.

With this feature, it is now possible to grant access to Fabric resources for a fixed period but it comes with a few limitations.

  • OneLake SAS are always short-lived, with a maximum lifetime of 1 hour.

  • OneLake SAS are always user-delegated, and must be backed by an Entra Identity.

  • OneLake SAS only grant access to folders and files within Fabric data items, like lakehouses.

Onelake SAS is compatible with Azure Storage tools and SDKs. So it supports both DFS and Blob endpoints and the account name for OneLake is always onelake.

In this example I will demonstrate the creation of SAS token through Azure SDK and highlight the error/issue I am facing. I will use the DFS endpoints to create a SAS token for access to a lakehouse in my Fabric tenant.

The Setup

I would use the same registered application for Entra ID that I used in one of my earlier article.

The next step is to enable three settings on your Fabric tenant

Of the above three settings, setting 2 and 3 are crucial in terms of managing the use of Onelake SAS.

** Setting 2 (Use short-lived user-delegated SAS tokens) It manages the generation of user delegation keys. User delegation keys are generated at the tenant-level and are controlled by a tenant setting.

** Setting 3 (Authenticate with OneLake user-delegated SAS tokens) is turned off by default and can be turned on by an admin who wants to allow authentication with a OneLake SAS in their workspace. A tenant admin can turn this setting on for all workspaces via the tenant setting, or leave it to workspace admins to turn on.

The Code

Create a new console application and declare a bunch of variables

 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 workspaceName = "Your Workspace";
 private static string lakeHouse = "Your LakeHouse";
 private static string endpoint = $"https://onelake.dfs.fabric.microsoft.com//{Your Workspace}//{Your LakeHouse}.LakeHouse/Files";
 private static ClientSecretCredential credential;
 private static DataLakeServiceClient datalake_Service_Client;
 private static DataLakeFileSystemClient dataLake_FileSystem_Client;

Method to return a Credential object for the Entra ID

  public static Task<ClientSecretCredential> ReturnCredentials(string baseUrl)
  {
      credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
      return Task.FromResult(credential);
  }

Call to the above method

  credential = await ReturnCredentials(endpoint);

Next, set the DataServiceClient

  datalake_Service_Client = new DataLakeServiceClient(new Uri(endpoint), credential);

Now we create a userDelegationKey.

The following method gets a user delegation key for the DFS service that is valid for 1 hour.

  public static Task<UserDelegationKey> RequestUserDelegationKey(DataLakeServiceClient datalakeServiceClient)
  {
          UserDelegationKey userDelegationKey =
           datalakeServiceClient.GetUserDelegationKey(
              DateTimeOffset.UtcNow,
              DateTimeOffset.UtcNow.AddHours(1));
      return Task.FromResult(userDelegationKey);
  }

Call for the above method :

 UserDelegationKey userDelegationKey = RequestUserDelegationKey(datalake_Service_Client).Result;

Next we define a method that will generate a Shared Access Signature (SAS) URI for the DFS resource using the UserDelegationKey that we created earlier.

We use the sasBuilder object and set the expiry period to one hour as OneLake SAS token by default supports only one hour till its expiry and set the permission level to read/write rw.The valid permission settings are rw, rd, rl, wd, wl, and rl.

  public static Task<Uri> CreateDfsSasUri(DataLakeServiceClient dfsClient, UserDelegationKey userDelegationKey)
  {
      DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder()
      {
          FileSystemName = dfsClient.AccountName,
          Resource = "c",
          StartsOn = DateTimeOffset.UtcNow,
          ExpiresOn = DateTimeOffset.UtcNow.AddHours(1)
      };

      sasBuilder.SetPermissions(DataLakeAccountSasPermissions.Read | DataLakeAccountSasPermissions.Write);
      string Sas = sasBuilder.ToSasQueryParameters(userDelegationKey, endpoint).ToString();
      Uri sasUri = new Uri($"{dfsClient.Uri}?{Sas}");

      return Task.FromResult(sasUri);
  }

The complete code

using Azure.Identity;
using Azure.Storage.Files.DataLake;
using Azure.Storage.Sas;
using UserDelegationKey = Azure.Storage.Files.DataLake.Models.UserDelegationKey;

namespace Fabric_SAS
{
    internal class Program
    {
      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 workspaceName = "Your Workspace";
      private static string lakeHouse = "Your LakeHouse";
      private static string endpoint = $"https://onelake.dfs.fabric.microsoft.com//Your Workspace//Your LakeHouse.LakeHouse/Files";
      private static ClientSecretCredential credential;
      private static DataLakeServiceClient datalake_Service_Client;
      private static DataLakeFileSystemClient dataLake_FileSystem_Client;

        static async Task Main(string[] args)
        {
            credential = await ReturnCredentials(endpoint);
            datalake_Service_Client = new DataLakeServiceClient(new Uri(endpoint), credential);
            UserDelegationKey userDelegationKey = RequestUserDelegationKey(datalake_Service_Client).Result;
            Uri sasUri = await CreateDfsSasUri(datalake_Service_Client, userDelegationKey);
            Console.WriteLine(sasUri);
        }

        public static Task<ClientSecretCredential> ReturnCredentials(string baseUrl)
        {
            credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
            return Task.FromResult(credential);
        }
        public static Task<UserDelegationKey> RequestUserDelegationKey(DataLakeServiceClient datalakeServiceClient)
        {

            UserDelegationKey userDelegationKey =
                 datalakeServiceClient.GetUserDelegationKey(
                    DateTimeOffset.UtcNow,
                    DateTimeOffset.UtcNow.AddHours(1));

            return Task.FromResult(userDelegationKey);
        }

        public static Task<Uri> CreateDfsSasUri(DataLakeServiceClient dfsClient, UserDelegationKey userDelegationKey)
        {
            DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder()
            {
                FileSystemName = dfsClient.AccountName,
                Resource = "c",
                StartsOn = DateTimeOffset.UtcNow,
                ExpiresOn = DateTimeOffset.UtcNow.AddHours(1)
            };

            sasBuilder.SetPermissions(DataLakeAccountSasPermissions.Read | DataLakeAccountSasPermissions.Write);
            string Sas = sasBuilder.ToSasQueryParameters(userDelegationKey, endpoint).ToString();
            Uri sasUri = new Uri($"{dfsClient.Uri}?{Sas}");

            return Task.FromResult(sasUri);
        }

    }
}

The Issue

Unfortunately, it isn't working for me. Without sufficient documentation it's difficult to pinpoint the exact issue. I'm not sure if it's a problem on my end or it is indeed a bug. The error message states that it expects bearer token, but if bearer token is expected then the entire purpose of having SAS token is defeated. With Shared Access Signature (SAS) token typically there is no need to send a bearer token in the request as the SAS token already contains the necessary authorization information such as permissions and the expiration time.

I checked the parameters of the request multiple times and they look fine to me

I have posted the issue in Microsoft fabric forum.

https://community.fabric.microsoft.com/t5/Data-Engineering/SAS-Token-in-fabric-Not-Working/m-p/4234190#M4501

Will update the article once I get a fix for the issue.

Thanks for reading !!!

More from this blog

My Ramblings On Microsoft Data Stack

88 posts

From Synapse Analytics, Power BI, Spark, Microsoft Fabric,ASP.NET Core and recently Agentic AI on .NET I try to explore, learn and share all aspects of Microsoft Data Stack in this blog.