Use pipe_through on Plug.Static to limit data access

I am curretnly using Elixir and the Phoenix Framework to build an API.
I want to make some files accessible with the api and I managed to use Plug.Satic to access the files but the problem is I can access them even if I am not logged in into the system

plug Plug.Static,
at: “img/files/”, from: “var/www/app/files/”, gzip: false

On all my routes defined in router.ex I use pipe_through [:authenticate] to limit the access to the data but I don’t know how to do it for the files urls.

Is it even possible ?

Thank you advance


Hi @Darkpingouin!

The router only invokes the pipelines for routes that it matches on. At the same time, plug Plug.Static works as a pass-through: i.e. if it finds a matching route, it serves it, otherwise it continues. So I am thinking you could probably do something like this in your router:

pipeline :static do
  plug Plug.Static, at: “img/files/”, from: “var/www/app/files/”, gzip: false

scope "/img/files" do
  pipe_through [:authenticate, :static]
  match "/*not_found", PageController, :not_found

In this case, if a static asset exists, it will be served. Otherwise, it will invoke PageController.not_found, which you can use to show a proper error message or just render the 404 page.

One other option is to not use Plug.Static at all and use Plug.Conn.send_file/3 directly.


Thanks for you answer, However when I try to use your method I get some page not found errors because it thinks I try to do some GET instead of just looking for the file

GET /img/files/img.png
Sent 404 in 80ms

I don’t know if I missed a step but I used your code I just remove the match “/*not_found” because I dont have any PageController in my project

The match "/*not_found" is extremely important, otherwise Plug.Static won’t be invoked, as the router only invokes the pipeline once a route is found. So you need to add it back and implement to do something, even if that something is returning 404.


Thank you very much, I actually had some compilation errors on

match “/*not_found”, PageController, :not_found

Because it was missing a parameter to call the function. I added :* like this :

match(:*, “/*not_found”, PageController, :not_found)

And it works just like I wanted.

Thank you very much for your help :slight_smile: