Grafana: OAuth2 Reverse Proxy - Wrong redirect URL

My Grafana instance is running behind a nginx reverse proxy. I access the reverse proxy over HTTPS and the reverse proxy pipes everything to the Grafana container over HTTP.

Now, I want to add authentication with OAuth2 and Azure AD as the provider. I have configured everything following the documentation, but I get the following error when Grafana login redirects me to the authentication provider:

AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application

I checked the request itself and found out that the request contains the wrong redirect url. The protocol is HTTP instead of HTTPS. This is probably because I connect with the reverse proxy using HTTPS and the proxy itself passes on the request without SSL (everything inside a Docker network).

Any idea what I should do? Maybe use HTTPS for the connection between the reverse proxy and Grafana?

Here is my grafana.ini:

[server]
domain = my.domain
root_url = %(protocol)s://%(domain)s:%(http_port)s/grafana/
serve_from_sub_path = true

[auth.azuread]
name = Azure AD
enabled = true
allow_sign_up = true
client_id = <id>
client_secret = ${AZURE_AD_CLIENT_SECRET}
scopes = openid email profile
auth_url = https://login.microsoftonline.com/<tenantid>/oauth2/v2.0/authorize
token_url = https://login.microsoftonline.com/<tenantid>/oauth2/v2.0/token

nginx.conf:

events {}
http {
  server {
    listen 443 ssl;
    root /usr/share/nginx/www;
    index index.html index.htm;
    ssl_certificate /etc/nginx/certs/promstack.crt;
    ssl_certificate_key /etc/nginx/certs/promstack.key;

    location /grafana/ {
      proxy_pass http://grafana:3000/;
    }

    location /prometheus/ {
      proxy_pass http://prometheus:3000/;
    }
  }
}

Thanks in advance

My Grafana instance is running behind a nginx reverse proxy. I access the
reverse proxy over HTTPS and the reverse proxy pipes everything to the
Grafana container over HTTP.

Okay.

Any idea what I should do?

Maybe use HTTPS for the connection between the reverse proxy and Grafana?

Sounds like the best idea to me.

You already have a certificate for the correct hostname, so you could most
easily just install the same certificate into Grafana and let the proxy trust
it the same as any browser does.

If, for whatever reason, you don’t want to put the real certificate into
Grafana, you could still create a self-signed certificate for Grafana to use,
and give the corresponding signing CA certificate to the proxy so that it
trusts it.

However, just out of interest, why did you set up a reverse proxy instead of
just doing HTTPS directly in Grafana to start with?

Regards,

Antony.

1 Like

Okay, I will setup Grafana for SSL and report back later.

why did you set up a reverse proxy instead of
just doing HTTPS directly in Grafana to start with?

I’m hosting this particular Grafana in a Docker Swarm as a stack together with Prometheus and Loki. Prometheus has a web interface but no support for TLS (https://prometheus.io/docs/guides/tls-encryption/) and the usage of a reverse proxy is recommended. So I decided to use Nginx for Grafana as well, just to have a single point of entry into the stack, so to speak.

You may have to set the root_url option of [server] for the callback URL to be correct.

You root_url is incorrect. You are using default “auto” option, so Grafana generates http because proxy is connecting to Grafana via http protocol. I would set:

root_url = https://%(domain)s:%(http_port)s/grafana/
1 Like

Okay. I have set root_url to https://%(domain)s/grafana/ and now I’m getting a connection timed out error on the Grafana instance. An oauth code is returned. But I don’t see the Login page of the auth provider (maybe because I am already logged in?). Here is a part of the Grafana logs:

lvl=info msg="Request Completed" logger=context userId=0 orgId=0 uname= method=GET path=/ status=302 remote_addr=10.0.77.13 time_ms=0 size=37 referer=

lvl=info msg="Request Completed" logger=context userId=0 orgId=0 uname= method=GET path=/login/azuread status=302 remote_addr=10.0.77.13 time_ms=0 size=391 referer=https://domain/grafana/login

lvl=info msg="state check" logger=oauth queryState=XXXXXXXXXXXXXXXXXXXXX cookieState=XXXXXXXXXXXXXXXXXXXXX 

lvl=eror msg=login.OAuthLogin(NewTransportWithCode) logger=context userId=0 orgId=0 uname= error="Post \"https://login.microsoftonline.com/UUUUUUUUUUUUUUUUU/oauth2/v2.0/token\": dial tcp 20.190.129.128:443: connect: connection timed out"

lvl=eror msg="Request Completed" logger=context userId=0 orgId=0 uname= method=GET path=/login/azuread status=500 remote_addr=10.0.77.13 time_ms=48072 size=1752 referer=https://domain/grafana/login

Looking at the network communication, the /authorize request seems to succeed. The redirect uri is correct. The response contains a code. Here things start to get wrong with an 500 Internal Server Error.

I guess I will drop the nginx and try it again

Does Grafana require internet access for OAuth2 to work? Because in my instance Grafana is not able to access the authentication provider (without a proxy).

See this question I asked on Stackoverflow: https://stackoverflow.com/questions/62248782/does-oauth2-require-internet-access-to-auth-provider-from-application-server/62249457#62249457

… I would say yes because Grafana does not hardcode signing keys? Sry, I’m an absolute beginner regarding this

No Grafana doesn’t. OIDC protocol (based on OAuth) needs that - now code must be exchanged for the token. Search “Authorization Code Grant Flow” to understand more.

You may try to configure env variables http_proxy, https_proxy with your proxy. It may help or not - it depends how is it implemented in the used auth library.

1 Like

Setting the env variables worked. And it doesn’t even interfere with Grafana accessing other services (Prometheus and Loki) in the Docker network, thanks everyone

Edit: It does interfere. I’m now using NO_POXY to exclude my datasources…