How can I protect static files with authorization on ASP.NET Core?
Tags: aspnetcore
Published: 2020-05-26 13:59:37

---
title: How can I protect static files with authorization on ASP.NET Core?
published: true
description: This article describes how to serve static files for only authenticated requests on the ASP.NET Core web application.
tags: aspnetcore
---

# I couldn't like the way of "Microsoft Docs" recommended to me...

A few weeks ago, I started a new ASP.NET Core web application project.

I had to protect static files with authorization on that application, but I had no idea how to implement it at that time.

Therefore, I started internet searching with the keywords "protect static files, authorization, asp.net core".

I got numerous search results, and many of the search results were questions and answers on "stackoverflow.com".

A part of those answers recommended us to try to one of the following solutions:

- (A) Insert ASP.NET Core middleware that your custom implementation into HTTP process pipeline at the before of static files middleware, and reject requests that aren't authorized.
- (B) Place static files you want to authorize to outside of "wwwroot", and serve it by ASP.NET Core MVC controller that your custom implementation, instead.

Especially, the solution (B) is explained by Microsoft official document site as you can see in the following URL:

- https://docs.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-3.1#static-file-authorization

However, I couldn't use those solutions for some reasons specified with the constraint of this project.

So, I continued reading the search results, and finally, I found the solution that I prefer.

The solution that I prefer is, hook the `OnPrepareResponse` call back point of static files middleware.

# "Static Files" middleware built-in ASP.NET Core provides a good hook point! 👍

When we register the "Static Files" middleware built-in ASP.NET Core into the HTTP process pipeline, we can also specify a `StaticFileOptions` option argument.

`StaticFileOptions` class has the property of a good hook point that allows us to insert a process before serving static files.

That property name is `OnPrepareResponse`.

We can set a call back function to the `OnPrepareResponse` property, then that function will be called back before serving each static file, and we can change the response rely on authorization state!

So I copied sample code from the answer on "stackoverflow.com" (following URL), and tried it.

- https://stackoverflow.com/a/51574637/1268000


Of course, we have to register "Authentication" middleware at the before of "Static Files" middleware to be available detect authenticated or not.

My sample code was like this:

```csharp
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  ...
  app.UseAuthentication();
  app.UseStaticFiles(new StaticFileOptions
  {
    OnPrepareResponse = ctx =>
    {
      if (!ctx.Context.User.Identity.IsAuthenticated)
      {
        // respond HTTP 401 Unauthorized.
        ctx.Context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
      }
      ...
```

# Oh, NO! Anyone can see my secret file!


I built my sample code and run it, but...

![fig.1](https://dev-to-uploads.s3.amazonaws.com/i/twvu0oi51jcpcra67p4h.png)

Oh, NO! Anyone can see my secret file!

My call back function exactly returned the "401 Unauthorized" HTTP status to the browser, but it didn't stop the response body!

# I have to stop the entire responding!

I have to not only return HTTP 401 but stop the entire of responding.

To do this, I appended 2 lines in my call back function like this:

```csharp
...
// respond HTTP 401 Unauthorized, and...
ctx.Context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;

// Append following 2 lines to drop body from static files middleware!
ctx.Context.Response.ContentLength = 0;
ctx.Context.Response.Body = Stream.Null;
..
```

This code drops the writing to the stream of response body from "Static Files" middleware, because that code replaces the body stream to `System.Null`.

The all of contents that wrote into `System.Null` is discarded, and it doesn't cause any effects.

Finally, I could protect the secret static files.

![fig.2](https://dev-to-uploads.s3.amazonaws.com/i/lr2xiickulzpr5ig5mce.png)

Please remember, to protect those secret static files, we have to concern browser caches.

In some cases, I could see the secret file from browser cache even if I wasn't authenticated after signed out from the application.

I avoided this problem by adding the "Cache-Control" header to the response.

```csharp
ctx.Context.Response.Headers.Add("Cache-Control", "no-store");
```

# If you want to redirect...

If you want to redirect to another page such as "Sign in" page instead of returning "HTTP 401", yes, you can do it by like this code:

```csharp
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  ...
  app.UseAuthentication();
  app.UseStaticFiles(new StaticFileOptions
  {
    OnPrepareResponse = ctx =>
    {
      if (!ctx.Context.User.Identity.IsAuthenticated)
      {
        // Can redirect to any URL where you prefer.
        ctx.Context.Response.Redirect("/")
      }
      ...
```



# Conclusion

- We can protect static files with authorization on the ASP.NET Core web application by using the `OnPrepareResponse` property of the options argument for "Static Files" middleware.
- Don't forget that place the calling `UseAuthentication()` at before of the calling `UseStaticFiles(...)`.
- We have to drop the entire of the response body from "Static Files" middleware when the request is unauthorized. 
- Please consider cache control to protect static files perfectly.
- We can also redirect to another page such as "Sign in" page instead of returning "HTTP 401".

The entire of my sample code is public on the GitHub repository of the following URL:

- https://github.com/sample-by-jsakamoto/ProtectStaticFilesWithAuthOnASPNETCore

The live demo site is also available on the following URL:

- https://protect-staticfiles-with-auth-on-aspnetcore.azurewebsites.net/

I'm happy if this article helps your ASP.NET Core programming life.

Happy coding :)