Google Asp.Net Core Authentication
My application is running on Google Compute Engine. Nginx is used as a proxy server. Nginx is configured to use SSL. Below is the content of / etc / nginx / sites -available / default:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name mywebapp.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
include snippets/ssl-mywebapp.com.conf;
include snippets/ssl-params.conf;
root /home/me/MyWebApp/wwwroot;
location /.well-known/ {
}
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
In Startup.cs I have:
app.UseGoogleAuthentication(new GoogleOptions()
{
ClientId = Configuration["Authentication:Google:ClientId"],
ClientSecret = Configuration["Authentication:Google:ClientSecret"],
});
Now in Google Cloud Platform, I need to specify the authorized redirect URIs. If I enter the following, my web app works as expected:
http://mywebapp.com/signin-google
But it won't work if used https
; the browser displays the following error:
The redirect URI in the request, http://mywebapp.com/signin-google, does
not match the ones authorized for the OAuth client.
In this case, is it safe to use http as the allowed uri redirect? What configuration do I need if I want it to be https?
source to share
This is because your reverse proxy application has no idea that the request was originally coming over HTTPS.
SSL / TLS proxy protocol
The reverse proxy configuration described in the question is called an SSL / TLS reverse proxy. This means that secure traffic is established between the client and the proxy server. The proxy server decrypts the request and then redirects it to the application over HTTP.
The problem with this configuration is that the application behind it doesn't know that the client has sent the request over HTTPS. So when it comes to redirecting to itself, it uses HttpContext.Request.Scheme
, HttpContext.Request.Host
and HttpContext.Request.Port
to create a valid redirect URL.
X-Forwarded- * HTTP Headers
Headers are used here X-Forwarded-*
. In order for the application to know that the request initially goes through the proxy server over HTTPS, we must configure the proxy server to set the HTTP X-Forwarded-For
and X-Forwarded-Proto
.
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
OK, now if we go back to our ASP.NET Core app and look at the incoming HTTP request, we can see that the headers are set X-Forwarded-*
, however, the redirect URL still uses the HTTP scheme.
Redirected Middleware Headers
Basically this middleware overrides HttpContext.Request.Scheme
both the HttpContext.Connection.RemoteIpAddress
values that were provided by the headers X-Forwarded-Proto
and X-Forwarded-For
appropriately. To make this happen, add it to the pipeline by adding the following line somewhere at the beginning of the method Startup.Configure()
.
var forwardedHeadersOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
RequireHeaderSymmetry = false
};
forwardedHeadersOptions.KnownNetworks.Clear();
forwardedHeadersOptions.KnownProxies.Clear();
app.UseForwardedHeaders(forwardedHeadersOptions);
Ultimately this should result in the correct URLs for your application being generated using the HTTPS scheme.
My story
The above code is different from what Microsoft suggests. If we look at the documentation , their code looks a little shorter:
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
However, this did not work for me. Also as per the comments in this question I am not alone.
I have nginx configured as a reverse proxy for an ASP.NET Core application running in a Docker container. This got complicated after I put everything behind Amazon Load Balancing (ELB).
I followed the documentation guidelines at first, but it didn't work for me. I have the following warning in my application:
Parameter mismatch between X-Forwarded-For and X-Forwarded-Proto
Then I looked at the titles X-Forwarded-*
and realized that they have different lengths. The header X-Forwarded-For
contained 2 entries (comma separated IP addresses) and X-Forwarded-Proto
only one entry https
. This is how I approached to set the property RequireHeaderSymmetry
to false
.
Well, I got rid of the "Parameter count ..." message, but right after that I ran into another odd debug message:
Unknown proxy: 172.17.0.6:44624
After going through the source code of ForwardedHeadersMiddleware , I finally figured out that I need to either clear both KnownNetworks
and the KnownProxies
collections, ForwardedHeadersOptions
or add my docker network 172.17.0.1/16
to the list of known networks. Right after that, I finally started working.
PS: For those setting SSL / TLS termination in a load balancer (like Amazon Load Balancer or ELB) DO NOT set the header X-Forwarded-Proto
in nginx config. This will override the correct value https
that comes from the load balance to the schema http
and the redirect url will be wrong. I have not yet found how to simply add the schema used in nginx to the header instead of overriding it.
source to share