NextJS Azure Services (Auth, SQL Database, Storage Account) Integration Problems

86 Views Asked by At

I'm attempting to build a Application with Services that should only be available to users within my Tenant. The biggest problem I'm coming across is that database connections are only working from the Static Web App Emulator (localhost:4280) and pulling from a Storage Account Container is only working from localhost:3000.

Current Resources

  • SQL Server
  • SQL Database
  • Storage Account
  • Static Web App
  • App Registered in Microsoft Entra ID

The first thing I did was setup the Static Web App and link it to the Repo which generated the CI/CD Workflow. Next, I attempted to tackle database. I created a staticwebapp.database.config.json file.
When starting the application with swa start http://localhost:3000 --run 'npm run dev' --data-api-location swa-db-connection, I'm able to see data I am pulling in from my SQL Database just fine.

The Storage Account is where it really got messy. Microsoft states:

"To use DefaultAzureCredential in a JavaScript app, add the @azure/identity package to your application."

// connect-with-default-azure-credential.js
import { BlobServiceClient } from '@azure/storage-blob';
import { DefaultAzureCredential } from '@azure/identity';
import 'dotenv/config'

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
if (!accountName) throw Error('Azure Storage accountName not found');

const blobServiceClient = new BlobServiceClient(
  `https://${accountName}.blob.core.windows.net`,
  new DefaultAzureCredential()
);

After attempting that, I discovered DefaultAzureCredential() does not work in the browser. You have to use InteractiveBrowserCredential which takes in a clientId and tenantId. I was able to eventually get this working but when moving pieces to a NextJS API Route to protect environment variables, that's where I ran into my next problem.

When I attempt to fetch NextJS API Routes from the emulator (localhost:4280), it's giving me a block in the terminal stating "Function request detected but no endpoint configuration was found. Please use the --api-location option to configure a function endpoint." If I use localhost:3000, these API Route calls work just fine.

My next problem is it seems when I use the , the popup window comes up and then in my terminal, I get an error stating "Token issued for the Single-Page Application client-type may only be redeemed via cross-origin requests".

What I'm looking to achieve is implementing to authenticate the user right up-front and then attempting to use that authentication for these other Azure Services in a seamless way.

I know I've got multiple different problems in here but any push in the right direction would help immensely. I've spent days reading documentation and looking for resources but I feel like I'm kind of stuck.

Thank you in advance!

1

There are 1 best solutions below

0
Sampath On BEST ANSWER

This Git issue concerns the use of Interactive Browser Credential for browser authentication in Identity. If Default Azure Credential is mentioned, it selects the credential based on the environment, as referred to in Stack Overflow.

The code for connecting to Azure Blob Storage using Azure.Identity is taken from this reference.



import React, { useEffect, useState } from 'react';
import { InteractiveBrowserCredential } from '@azure/identity';
import { BlobServiceClient, BlobItem } from '@azure/storage-blob';

interface BlobViewProps {}

const BlobView: React.FC<BlobViewProps> = () => {
  const [blobsWeFound, setBlobsWeFound] = useState<BlobItem[]>([]);
  const [containerUrl, setContainerUrl] = useState<string>('');

  useEffect(() => {
    const signInOptions = {
      clientId: 'clientId', // Your application client ID
      tenantId: 'tenantId', // Your Azure AD tenant ID
    };

    const fetchBlobData = async () => {
      try {
        const blobStorageClient = new BlobServiceClient(
          'https://<your-storage-account-name>.blob.core.windows.net/',
          new InteractiveBrowserCredential(signInOptions)
        );

        const containerClient = blobStorageClient.getContainerClient('private');
        const blobList: BlobItem[] = [];

        for await (const blob of containerClient.listBlobsFlat()) {
          blobList.push(blob);
        }

        setBlobsWeFound(blobList);
        setContainerUrl(containerClient.url);
      } catch (error) {
        console.error('Error fetching blob data:', error);
      }
    };

    fetchBlobData();
  }, []);

  return (
    <div>
      <table>
        <thead>
          <tr>
            <th>blob name</th>
            <th>blob size</th>
            <th>download url</th>
          </tr>
        </thead>
        <tbody>
          {blobsWeFound.map((blob, index) => (
            <tr key={index}>
              <td>{blob.name}</td>
              <td>{blob.properties?.contentLength}</td>
              <td>
                <img src={`${containerUrl}${blob.name}`} alt={blob.name} />
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

export default BlobView;


The Next.js documentation should include a section on configuring CORS (Cross-Origin Resource Sharing) for API routes. This will enable communication between your application's frontend (localhost:4280) and the API routes (localhost:3000).

enter image description here