Back

Technologies:

javascriptjavascript
reactjsreactjs
avatar
Tolerim
a month ago

What is the process for showcasing a protected image using an Authorization Header in NextJS?

I have created a NextJS app that displays images. To authenticate my requests for images, I need to include an Authorization Header with a Bearer Token. This works correctly when I try it using Postman. However, I am unsure how to display this image in a <img> tag within my NextJS app. Since the app uses Server Side Rendering, do I need to "use client" to make it work? Even when I create a Blob, I still receive a "net::ERR_ABORTED 401 (Unauthorized)" error, even though the Token is valid. Here's the code block I have:

const [path, setPath] = useState();

useEffect(() => {
    const src = 'http://example.com/test.jpg';
    const options = {
        headers: {
            'Authorization': 'Bearer 123456',
            "Content-Type": "image/jpeg"
        },
        mode: 'no-cors',
        cache: 'no-store',
        method: "GET"        
    };
    fetch(src, options)
    .then(res => res.blob())
    .then(blob => {
        const toBlob = URL.createObjectURL(blob);
        setPath(toBlob);
    });
}, [])
I believe the issue might be because of the 401 error. Is there a way to display an image that is protected by the Auth header? Please let me know. Thank you.

Answers(2)
avatar
Vogi
a month ago
Verified Answer
You can use the next/image component in Next.js to display images. The next/image component is an extension of the HTML element that provides advanced image optimization capabilities. You can use the headers property of the ImageProps object to pass the authorization header with the Bearer token. Here's an example:
import Image from 'next/image';

const MyImage = () => {
  return (
    <Image
      src="http://example.com/test.jpg"
      alt="Test Image"
      width={500}
      height={500}
      headers={{
        Authorization: 'Bearer 123456',
        'Content-Type': 'image/jpeg',
      }}
    />
  );
};
You can also use the fetch() method to get the image and convert it into a blob. Then you can create a URL object using the URL.createObjectURL() method and set it as the source of an tag. Here's an example:
import { useState, useEffect } from 'react';

const MyImage = () => {
  const [path, setPath] = useState();

  useEffect(() => {
    const src = 'http://example.com/test.jpg';
    const options = {
      headers: {
        Authorization: 'Bearer 123456',
        'Content-Type': 'image/jpeg',
      },
      mode: 'no-cors',
      cache: 'no-store',
      method: 'GET',
    };
    fetch(src, options)
      .then((res) => res.blob())
      .then((blob) => {
        const toBlob = URL.createObjectURL(blob);
        setPath(toBlob);
      });
  }, []);

  return <img src={path} alt="Test Image" />;
};
I hope this helps! Let me know if you have any other questions.

Sources

next/image | Next.jsHow to display Image protected by Authorization Header in NextJS?How to display an image protected by header-based authenticationjavascript - Authorization header in img src link - Stack Overflow
avatar
Tolerim
a month ago
Since your NextJS app is server-side rendered, you can't directly access the token from the client side. Here's a solution to your problem: First, you need to create a server-side API route that will receive the authorization token and the image URL, and then fetch the image with the token. Here is an example:
import fetch from 'isomorphic-unfetch';

export default async (req, res) => {
  const { url, token } = req.query;

  const image = await fetch(url, {
    headers: { Authorization: `Bearer ${token}` },
  }).then((r) => r.buffer());

  res.setHeader('Content-Type', 'image/jpeg');
  res.setHeader('Cache-Control', 'max-age=31536000, public');
  res.send(image);
};
Then, on the client side, you need to fetch the image from this route instead of directly from the source. Here's an example:
const [path, setPath] = useState();

useEffect(() => {
  const src = 'http://example.com/test.jpg';
  const token = '123456';
  const url = `/api/image?url=${encodeURIComponent(src)}&token=${token}`;

  fetch(url).then((res) => {
    const toBlob = URL.createObjectURL(res.blob());
    setPath(toBlob);
  });
}, []);
In this example, we first create a URL for the server-side route with the image URL and the token as query parameters. We then fetch the image from this URL, which should return the image with the authorization header set. Finally, we create a blob URL from the response and set it as the src of the img element.
;