Use own JWT in grafana

Hi,
Our site retrieves a JWT from keycloak when the user logs in.
This JWT is stored in the browser storage.

We are having, amongst other pages, a grafana dashboard.
We would like grafana to use our JWT for all its API calls. We have an authentication service in front of it.

For it to work in our service we need it to have the Authorization header and X-Original-Uri header.
If grafana can pass these headers with the necessary info, our auth service will handle them and we shoudn’t need grafana to do anything besides handle its API call.

How can we achieve this? We can have the JS set data in the browser in some other many if need be.

I found the following issues that look similar to our needs.


Any help or information would be great!

Thank you!

IMHO: use Grafana in Auth proxy mode + add properly configured keycloak-gatekeeper in front of Grafana -> standard cookies will be used.

Definitely better, than hacking Grafana source code only to add special headers for obscure authN/authZ system (I hope your don’t need that, because your request is only about JWT :slight_smile: ).

1 Like

Hi, we decided to use embedded and load grafana in an iframe.
Now the parent can refresh the token and update the cookie.
This is proving to work rather well.

I just thought there would be a way to use the header, but even then I realize once that JWT expires, it still needs to be refreshed, which is a whole other issue.

Hi Michael
How did you embed Grafana into an iFrame? Is the look and feel of Grafana intact that way?
Is that the best approach you think? We also have a system where JWT token is basically user authentication thrown everywhere, and the question right now is how can Grafana handle this; can it forward tokens to the backend as headers directly? Please share if you have some details on both options?
Thanks
Rajesh

We use a basic iframe in angular to load grafana.
The url it loads is like:

this.url = 'https://' + subdomain + '.' + this.base_url +'/?user=' + username + '&token=' + token + '&realm=' + this.realm;

and the html is like"

<div class="iframe-wrapper"><iframe [src]="urlSafe" (load)="loadediframe()"></iframe></div>

The reason to have the querystring is because grafana uses cookies and our angular app is doing the jwt auth and refresh then after the angular refreshes the token, it updates the cookie with the new token so grafana does not get logged out.

There is some stuff in the backend with the nginx config also to set the cookies and such.

The look is fine since you can style the page around the iFrame however you want.

It is not ideal though because mobile browsers do not allow the iframe.

I do not know if it is the best approach but it works for now.

Hi Micheal,

I am using Grafana and Nginx for proxy authentication, and as what you have described above, I am also using angular 8 in my app. My use case is pretty similar to your’s, as I am invoking Grafana from my app using Nginx which is acting as a proxy in front of grafana, for e.g.

My angular 8 application -> Nginx proxy -> Grafana

But I am facing issues as I am not able to launch Grafana from my app with authlogin authentication, Could you please advise where I am going wrong? Thanks for your help in advance.

Here is my code -

Nginx code:
location /grafana/ {
set $username “user1”;
auth_request_set $user $upstream_http_user;
add_header X-uri “$username”;
proxy_set_header X-WEBAUTH-USER $username;
proxy_set_header Authorization “”;
proxy_pass http://localhost:3000/;
}

Angular 8 app code using iframe to invoke grafana:

iframe src=“https://localhost:4200/grafana/

Grafana config:

grafana:
container_name: “grafana-dashboard”
image: grafana/grafana:6.7.4
ports:
- “3000:3000”
volumes:
- “~/workspace/docker_volumes/grafana:/var/lib/grafana”
- “./grafana/conf/dashboards.yml:/etc/grafana/provisioning/dashboards/dashboards.yml”
- “./grafana/conf/dashboard.json:/var/lib/grafana/dashboards/dashboard.json”
links:
- pgdb
networks:
- default
environment:
- GF_SERVER_ROOT_URL=http://127.0.0.1:300/
- GF_AUTH_PROXY_ENABLED=true
- GF_AUTH_PROXY_HEADER_NAME=X-WEBAUTH-USER
- GF_AUTH_PROXY_HEADER_PROPERTY=username
- GF_AUTH_PROXY_AUTO_SIGN_UP=true
- GF_SECURITY_ALLOW_EMBEDDING=true
- GF_DATABASE_TYPE=postgres
- GF_DATABASE_HOST=pgdb:30218
- GF_DATABASE_SSL_MODE=disable
- GF_DATABASE_BASIC_AUTH=false
- GF_DATABASE_NAME=grafana
- GF_DATABASE_USER=postgres
- GF_DATABASE_PASSWORD=password
- GF_USERS_DEFAULT_THEME=light
restart: unless-stopped

My angular 8 app, Nginx, and Grafana is running as a docker container.

Thanks,
Ketan

Honestly I probably can not. I just helped another developer with this and she did most of the work.

Are you setting the cookie in your angular app?
Part of our nginx config looks like so:

location / {

           set $user $cookie_grafana_user;
           set $token $cookie_grafana_token;
           set $realm $cookie_grafana_realm;


           if ($arg_token){
               add_header Set-Cookie "grafana_token=$arg_token; Domain=.<redacted>.com; Path=/" always;
               add_header Set-Cookie "grafana_realm=$arg_realm; Domain=.<redacted>.com; Path=/" always;
               add_header Set-Cookie "grafana_user=$arg_user; Domain=.<redacted>.com; Path=/" always;
               set $user $arg_user;
               set $token $arg_token;
               set $realm $arg_realm;

            }
            proxy_set_header X-WEBAUTH-USER $user;
            proxy_pass http://<IP>:<PORT>;
            auth_request /auth;
            auth_request_set $auth_status $upstream_status;


        }

    location /auth {
            internal;
            proxy_pass "http://<IP>:<PORT>/gfauthenticate";
            proxy_pass_request_body "off";
            proxy_set_header Content-Length "";
            proxy_set_header X-Original-URI $realm&$token&$user;

            }

So we are authorizing it through keycloak.

I hope that helps.

hey iam using react to display grafana using iframe i send auth token in query params to by backend which display the basic grafana dashboard but all other api call which iframe made shows un authorize can you help me how to solve this issue?