skip to Main Content

I’m working on developing an API that allows users to retrieve blobs from Azure Storage (RBAC) using Azure AD OAuth2 authentication. Here’s the scenario:

  • Users will authenticate using Azure AD OAuth2 (Authorization Code flow keeping scope as access-as-user) it generates Bearer access_token.
  • The API takes parameters such as Storage Account (SA), Container, and Blob Path.
  • Users may have read access to multiple storage accounts, and some may have access to only one storage account.

I need to ensure that the API returns a blob is user has access else return Auth Error if the authenticated user doesn’t have permission to access a specific blob in the requested storage account and container.

I’m creating a blob client based on these details with this .NET Code.

 Uri blobUri = new Uri($"https://{storageAccountName}.blob.core.windows.net/{containerName}/{filePath}");
 BlobClient blobClient = new BlobClient(blobUri, new DefaultAzureCredential());

The issue is I’m able to access the required blob if I’m running this in my local dev setup (I have to do az login in Azure Cli). But when I try to run it in Deployed app on Azure then it gives 403 error.

I’ve have made sure that user at least have Blob Reader Access & reader access in resource group. I have given delegation user_impersonation api permissions for Azure Storage

Doc used for reference: https://learn.microsoft.com/en-us/dotnet/azure/sdk/authentication/?tabs=command-line

Any guidance or code examples on how to implement this securely and efficiently would be greatly appreciated. Thank you!

2

Answers


  1. Once deployed, your app will ressort to Managed Identity or Service Principal authentication. Ensure the former has proper permissions for storage resources.

    Login or Signup to reply.
  2. The reason why the following code works in your local environment is because there it is using your credentials (assuming you are already logged in) and not using the token you sent through API call.

    BlobClient blobClient = new BlobClient(blobUri, new DefaultAzureCredential());
    

    For the same reason, it fails when your code is running in the App Service. Because your App Service does not have any RBAC role assigned on the storage account, you will get 403 error.

    If you want to use the user’s access token, the way you would solve this problem is by creating a custom class extending TokenCredential (DefaultAzureCredential extends TokenCredential).

    The code would be something like the following:

    /// <summary>
    /// Creates a token credential class using an access token.
    /// </summary>
    public class AccessTokenCredential : TokenCredential
    {
      /// <summary>
      /// Creates an instance of <see cref="AccessTokenCredential"/>.
      /// </summary>
      /// <param name="accessToken">
      /// JWT encoded access token.
      /// </param>
      public AccessTokenCredential(string accessToken)
      {
          AccessToken = accessToken;
      }
      
      /// <summary>
      /// Gets the access token.
      /// </summary>
      private string AccessToken { get; }
    
      /// <summary>
      /// 
      /// </summary>
      /// <param name="requestContext"></param>
      /// <param name="cancellationToken"></param>
      /// <returns></returns>
      public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
      {
          return new ValueTask<AccessToken>(GetAccessToken());
      }
    
      /// <summary>
      /// 
      /// </summary>
      /// <param name="requestContext"></param>
      /// <param name="cancellationToken"></param>
      /// <returns></returns>
      public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
      {
          return GetAccessToken();
      }
    
      /// <summary>
      /// Validates access token and returns <see cref="AccessToken"/>.
      /// </summary>
      /// <returns>
      /// <see cref="AccessToken"/>.
      /// </returns>
      /// <exception cref="ArgumentException">
      /// Access token is invalid.
      /// </exception>
      private AccessToken GetAccessToken()
      {
          JwtSecurityToken token = new JwtSecurityToken(AccessToken);
          return new AccessToken(AccessToken, token.ValidTo);
      }
    }
    

    and your code will be something like:

    BlobClient blobClient = new BlobClient(blobUri, new AccessTokenCredential("your-access-token"));
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search