Search code examples
javascriptreactjsazureazure-blob-storageazure-sas

How can I use token instead of azure connection string for blob storage access


I want to implement a feature to upload recorded audio blob data to the azure blob storage in frontend(react.js). I have azure storage connection string, but I dont want to my connection string to be exposed in frontend. Is there any way to define an backend API to generate token(which has expiration time) from azure credentials so that I can use it in the Frontend? Do I need additioinal settings from azure account?

Ps. similar to this one. For azure speech cognitive sdk, there is a api to issue tokens using speech region and speech key. https://{SPEECH_REGION}.api.cognitive.microsoft.com/sts/v1.0/issueToken

I tried to use sas token but it seems to be very complex.


Solution

  • How can I use a token instead of Azure connection string for blob storage access

    Yes, you can create a backend API to generate a SAS token for your Azure Blob Storage account. This way, you can keep your connection string and account key secure on the server side and only expose the SAS token to the front end.

    you can use the below code to upload audio files using the sas token from the backend.

    First, create a backend directory to generate sas-token.

    mkdir backend 
    cd backend
    

    Package:

      npm install express
      npm install @azure/storage-blob
      
    

    server.js

    const express = require('express');
    const app = express();
    const cors = require('cors');
    const { BlobServiceClient, StorageSharedKeyCredential, generateAccountSASQueryParameters, AccountSASPermissions, AccountSASServices, AccountSASResourceTypes, SASProtocol } = require('@azure/storage-blob');
    
    const accountName = 'your-account-name';
    const accountKey = 'your-account-key';
    
    const sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);
    const blobServiceClient = new BlobServiceClient(`https://${accountName}.blob.core.windows.net`);
    
    app.use(express.json());
    app.use(cors({ origin: 'http://localhost:3001' }));
    
    app.get('/generate-sas-token', async (req, res) => {
      const { blobName } = req.query;
    
    
      const sasOptions = {
        expiresOn: new Date(Date.now() + 3600 * 1000), // Expires in 1 hour
        permissions: AccountSASPermissions.parse('racwd'),
        services: AccountSASServices.parse('bf').toString(), // Blobs only
        resourceTypes: AccountSASResourceTypes.parse('sco').toString(), // Service, Container, and Object
        protocol: SASProtocol.HttpsAndHttp
      };
    
      const sasToken = generateAccountSASQueryParameters(sasOptions, sharedKeyCredential).toString();
      res.json({ sasToken });
      console.log(sasToken);
    });
    
    const port = process.env.PORT || 3000;
    app.listen(port, () => {
      console.log(`Server is running on port ${port}`);
    });
    

    Start the backend API by running the following command in the backend directory:

    node server.js
    

    Now front end uses the React app.

    Package:

    npm install axios
    

    AudioUploader.js

    import React, { useState } from 'react';
    import axios from 'axios';
    
    
    function AudioUploader() {
      const [selectedFile, setSelectedFile] = useState(null);
      const [sasToken, setSasToken] = useState('');
      const [uploadStatus, setUploadStatus] = useState('');
    
      const handleFileChange = (event) => {
        setSelectedFile(event.target.files[0]);
      };
    
      const generateSasToken = async () => {
        try {
          const response = await axios.get(`/generate-sas-token?blobName=${selectedFile.name}`);
          setSasToken(response.data.sasToken);
        } catch (error) {
          console.error('Error generating SAS token:', error);
        }
      };
    
      const uploadAudio = async () => {
        if (!sasToken || !selectedFile) {
          console.error('SAS token or file not selected.');
          return;
        }
    
        const blobUrl = `https://<Your-storage>.blob.core.windows.net/<container-name>/${selectedFile.name}?${sasToken}`;
        const headers ={'x-ms-blob-type': 'BlockBlob'};
        try {
          await axios.put(blobUrl, selectedFile,{headers});
          setUploadStatus('Upload successful!');
        } catch (error) {
          console.error('Error uploading audio:', error);
          setUploadStatus('Upload failed.');
        }
      };
    
      return (
        <div>
          <h2>Audio Uploader</h2>
          <input type="file" onChange={handleFileChange} />
          <button onClick={generateSasToken}>Generate SAS Token</button>
          {sasToken && (
            <div>
              <button onClick={uploadAudio}>Upload Audio</button>
            </div>
          )}
          {uploadStatus && <p>{uploadStatus}</p>}
        </div>
      );
    }
    
    export default AudioUploader;
    

    Output: enter image description here

    Browser:

    enter image description here

    Portal:

    enter image description here

    Here is my GitHub link to upload audio files to Azure blob storage with backend API using javascript.