Orthanc asks for username/password when loading instance preview in browse

Hello everyone, hope you’re doing well.,

I am using Orthanc with authentication enabled and accessing it from a Django backend using pyorthanc.

From Django, I successfully authenticate and fetch study/series metadata like this:

server = Orthanc(“https://pacs.example.com”, username=“admin”, password=“****”)
study = server.get_studies_id(study_id)

This works correctly.

However, when I send the instance preview URL to the frontend:

https://pacs.example.com/instances/{instanceId}/preview

and load it in the browser (e.g. using an tag), Orthanc always prompts for username/password.

I also tried embedding the credentials directly in the URL, like:

https://username:password@pacs.example.com/instances/{instanceId}/preview

but this results in a 401 Unauthorized response and does not work in the browser.

What is the recommended way to serve instance preview images in a web application without triggering the Orthanc login prompt?

Hello,

This is expected, as HTTP basic authentication is automatically enabled as soon as RemoteAccessAllowed is set to true. As a highly insecure solution, you could set AuthenticationEnabled to false. Do not do this in production, as anybody will be allowed to access the full REST API.

The recommended option is to put a reverse proxy (nginx or Apache, yet your Django application) in front of Orthanc and let it handle authentication and authorization. In this case, the Orthanc server can run in a “service mode”, using credentials that are only known to your reverse proxy.

Kind Regards,
Sébastien-

Thank you for the suggestion, Jodogne.

I already have Nginx running in front of Orthanc as a reverse proxy. When I hard-code the Orthanc credentials in the Nginx configuration, everything works as expected. However, when I remove the hard-coded credentials and try to handle authentication in a more dynamic way, I start encountering the issue I described earlier, particularly with serving preview images.

My main concern with hard-coding credentials in the Nginx configuration is that, even in this case, anyone who can access the proxy endpoint may still be able to access the full REST API. Please correct me if my understanding is not accurate.

We have already experienced bot and attack attempts with this setup, which is why we would prefer not to continue using this structure. I would really appreciate your guidance on a more secure approach for handling this,

This is not accurate, as you can rely on nginx to add authentication to endpoints, including those served by a reverse proxy. In your nginx configuration, you can for instance attach the auth_basic directive to the location that uses proxy_pass.

Hello @Akash123 - you could do something like this. we found nginx auth_request works really well -

location /orthanc/ {

  if ($orthanc_preflight_ok) {
    add_header Access-Control-Allow-Origin      $cors_allow_origin always;
    add_header Access-Control-Allow-Methods     'GET, POST, PUT, PATCH, DELETE, OPTIONS' always;
    add_header Access-Control-Allow-Headers     $http_access_control_request_headers always;
    add_header Access-Control-Allow-Credentials 'true' always;
    add_header Access-Control-Max-Age           1728000 always;
    add_header Content-Type                     'text/plain; charset=utf-8' always;
    add_header Content-Length                   0 always;
    return 204;
  }
  if ($request_method = OPTIONS) { return 204; }

  auth_request /auth;

  include               /etc/ssl/certs/proxy-settings.conf;
  proxy_pass            http://orthanc/;
  proxy_next_upstream   error timeout;
  proxy_set_header      Host $host;
  proxy_set_header      Connection "";
  proxy_set_header Authorization "$ORTHAUTH";

  include /etc/ssl/certs/ifcors.conf;

  include       /etc/ssl/certs/general-security-headers.conf;
  expires       0;
  add_header    Cache-Control private;
}

  location = /auth {
    internal;
    include               /etc/ssl/certs/proxy-settings.conf;
    proxy_pass            http://auth/validate;
    proxy_next_upstream   error timeout;
    proxy_set_header      Host $host;
    proxy_set_header      Connection "";
    proxy_set_header      Cookie $http_cookie;

    proxy_pass_request_body off;
    proxy_set_header      Content-Length "";
    proxy_set_header      X-Original-URI $request_uri;
  }

Hi Oliver, thank you for your recommendation. I will try this and let you know.