Building a Reverse Proxy in .NET Core

This article will show how to implement a reverse proxy in C# within the .NET Core environment to overcome specific needs that you could hardly solve with an out-of-the-box software.

Read more at:

1 Like

How did you like this article? Please share any comments or feedback with us on this thread :slight_smile:

1 Like

Thanks for this. As an extension, maybe what it would look like to add a transparent WebSocket reverse proxy as well.

1 Like

Hello, Reverse proxy is indeed a powerful pattern. We use a reverse proxy to enable all of our oAuth flows to legacy and oAuth enabled applications. The reverse proxy initiates auth code with PCKE and can convert ID and access token claims values into simple headers. Configuration switches support sending only headers, headers + Access and ID tokens, or Just Id and Access tokens. Likewise the proxy can take the simple web token from a legacy application and turn it into an inbound federated SAML request when launching into an oAuth enabled platform. This supports true SSO between a legacy platform using simple web tokens and an oAuth enabled app using JWT tokens. would love to see auth0 add something like that to their product stack.

Hey there @jonathanandrewnewell! Thanks a lot for providing such feedback. Can I ask you to route it to our product managers via our product feedback form (you should be contacted within 10 business days):

Make sure to provide us much context about the usecase as possible so the team have proper justification for potentially implementing it in the future. Thank you!

@andrea.chiarelli thanks for this! I’ve been trying to make a .net core application load WordPress from a separate website under /blog for probably a day now. This post helped me accomplish this :slight_smile: I am yet to upload to Azure, but since it’s working on localhost it should be fine. Once again, thanks! Other similar articles didn’t help.

1 Like

Hey @weirddreaming,
Thank you so much! I’m very happy to hear it helped you!

1 Like

A great tutorial however, the google form structure seems to have changed since this was originally written. There are two different gstatic URI patterns now and the Freebird script doesn’t seem to convert (Freebird values also change everytime page loads). How could this be handled?:

Reverse Proxied =

Throws a GET 400 on my test rig console =

m=viewer_base:531
GEThttps://localhost:44392/googlestaticfreebird//freebird//js/k=freebird.v.en_GB.bVKgu9uYWpY.O/d=0/ct=zgms/rs=AMjVe6i_MTGX4_zWWNVVpUGyTtks0AA6iQ/m=NpD4ec,ws9Tlc,sy0,sy16,sy17,sy1,sy18,sy3n,sy2y,sy3o,V3dDOb,sy27,gkf10d,j2YlP,sy7,sye,syd,sya,sy8,sy2q,sy9,sy2s,OShpD,J8mJTc,sy19,eFy6Rc,sy2,CP1oW,sy20,De38hd,Sk9apb,syy,sy2w,sy3k,sy5t,KornIe,sy2f,gZjhIf,syp,syn,sy1f,sy1m,syj,sy1n,sy4b,sy54,pxq3x,sy11,sy2e,sy6n,O6y8ed,syf,sy4m,syb,syc,syg,sy2k,sy4n,sy4t,sy4,sy2l,sy2o,sy4o,sy4v,sy2p,sy4x,mRfQQ,sy4e,sy4g,sy4f,CFa0o,Q91hve,sy4k,Y9atKf,sy4z,s39S4,sy5u,wPRNsd,sy67,L1AAkb,sy44,sy7u,xQtZb,QvB8bb,bCfhJc,sy43,sy4j,syl,sy4i,sy50,yZuGp,bjxBRd,sy6q,aW3pY,sy7t,rHjpXd,sy2u,sy2x,sy31,sy6r,I6YDgd,sy1g,sy1h,sy1i,sy1j,sy1o,sy45,sy1e,sy1k,sy1l,sy3l,sy3p,sy46,sy4d,sy83,sy84,fgj8Rb,sy7s,SM1lmd,IvDHfc,sy1d,sy1s,sy1t,p2tbsc,d8PXFf,atgb9d,LxALBf,JCrucd,sy3a,sy2z,sy37,sy38,sy3b,sy3c,sy30,sy34,sy2m,sy4p,sy4q,sy2g,sy3u,sy4h,sy4r,sy4s,sy52,sy51,sy32,sy33,sy35,sy36,sy39,sbHRWb,sy53,OkF2xb,WdhPgc,QwQO1b,sy1y,xajb8d,ok0nye,sy3g,sy59,sy5p,sy5q,lSvzH,TOfxwf,oZECf,yUS4Lc,sy4w,KOZzeb,OqIWSb,sy3m,sy5n,sy55,sy5o,UmOCme,oCiKKc 400

Oops - example code was stripped. Lets try again:

Original firebird script in Google form =

 "script id="base-js"src="https://www.gstatic.com/_/freebird/_/js/k=freebird.v.en.rw5RzQvJS20.O/d=1/ct=zgms/rs=AMjVe6iaRaZcebPo3taCRaE9rnrlRY0qcg/m=viewer_base" nonce=""></script"

Reverse Proxied pattern =
“script id=“base-js” src=”/googlestaticfreebird//freebird//js/k=freebird.v.en_GB.bVKgu9uYWpY.O/d=1/ct=zgms/rs=AMjVe6i_MTGX4_zWWNVVpUGyTtks0AA6iQ/m=viewer_base" nonce=“”></script"

Hey @MartinSansone,
Thank you for reading the article and reporting the issue.
I will try to fix it as soon as I can.

Consider that the goal of the article is to give you an idea about how to create a simple reverse proxy in .NET Core. It is not meant to create a complete reverse proxy like Nginx, for example.
So, it doesn’t take into account many aspects of the HTTP protocol. This means that, if things change on the target server, most likely you have to change something in your middleware. Not so great… :slight_smile:
As said in the article, when possible, you should use standard tools as a reverse proxy. You should try to implement your own in very specific cases. Better if you also have the target server under your control.

1 Like

Hi @andrea.chiarelli
What is the reason for removing transfer-encoding from Response Header?

Hi @david.pg18, welcome to Auth0 Community and thanks for reading my article!
Regarding your question, the transfer-encoding header is set by web servers, gateways, and other nodes at the transport layer. It is a hop-by-hop header and can be used, for example, to transfer messages by chunks.
As such, it must not be retransmitted by proxies.
To know more about the transfer-encoding header, please check the MDN documentation.
I hope this answers your question sufficiently.

2 Likes

Thank you so much for this article. I was able to use this to pretty much as is.
I came across an issue where an api was returning a 301 where it should have returned a 404 (don’t ask). When HttpClient tried redirecting I ran into issues because the 301 destination was an actual 404 page and couldn’t handle the original request. The result was that I got a 500 instead of the 404. Yes, the issue is the api being called, but I had no control over that. I was able to overcome this issue by adding the following code:

        var handler = new HttpClientHandler()
        {
            AllowAutoRedirect = false
        };
        _httpClient = new HttpClient(handler);

I’m thinking that a reverse proxy should always return exactly what the target returns and not attempt the redirect.

Hello, it is perfectly working for me but…
when I use identity server , it sees the proxy as always the same session.
In this case I can only use one user at time on the whole app.
It has to do with “X-Forwarded” Headers I think

Any ideas? :slight_smile:

Folks ending up on this post may want to checkout YARP instead, full reverse proxy capabilities and it’s all configurable with minimum code (GitHub - microsoft/reverse-proxy: A toolkit for developing high-performance HTTP reverse proxy applications.).

1 Like

Thanks for sharing that with the rest of community!

1 Like

Hi Andrea, a nice post, thanks; but I’m wondering if (at least in the case of .NET 6) you are missing the following, after copying the content:

            if (context.Request.ContentType != null)
            {
                requestMessage.Content.Headers.ContentType =
                    MediaTypeHeaderValue.Parse(
                        context.Request.ContentType);
            }

            requestMessage.Content.Headers.ContentLength =
                context.Request.ContentLength;

And whether you meant to also exclude the reference to the “Content” property when copying the headers (- e.g. for properly copying the ‘Authorization’ header for example):

requestMessage.Headers.TryAddWithoutValidation(header. Key, header.Value.ToArray());

Hey @DennisVM-D2i,
Welcome to the Auth0 Community :wave: and thank you for reading my article.
Honestly, I’m not sure I understand your suggestion. I actually copy all content headers :thinking:
Do you get any issues?

In any case, consider that the sample code of this article targets .NET 2.1, so maybe something may be changed in the meantime :slightly_smiling_face:

1 Like