Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic login by token url #3752

Closed
german-bortoli opened this issue Jan 15, 2016 · 120 comments
Closed

Automatic login by token url #3752

german-bortoli opened this issue Jan 15, 2016 · 120 comments
Assignees
Labels
area/auth help wanted prio/medium Important over the long term, but may not be staffed and/or may need multiple releases to complete. prio/unscheduled type/feature-request

Comments

@german-bortoli
Copy link

Should be nice to have an automatic login passing an user token thru url, this could be a partial solution to embed iframes on sites.

@torkelo
Copy link
Member

torkelo commented Jan 15, 2016

would be pretty insecure as anyone can see the token, you can create a snapshot of the visible data and embedd that, it would be more secure

@torkelo torkelo closed this as completed Jan 15, 2016
@german-bortoli
Copy link
Author

Yes but using snapshots you don't have the permission to edit it, or is there any way to edit dashboard thru snapshots ?

@adamlwgriffiths
Copy link

This is pretty important for interoperability with SaaS.
We have our own authentication and dashboards, we want to provide the ability to pass a user from our dashboard across to Grafana - in a similar vein to how Heroku interoperates with New Relic and other services with zero-passwords.

Providing a url+token authentication method is par-for-the-course.
If someone then goes and embeds that on a public website, then no amount of security will save that person from themself. That's their fault.
Providing sufficient warnings in documentation / UI should be fine for this.

Without this functionality, users must encounter a second login screen, where they will be confused as to what username / password to enter.

This is a big blocker for us.

@torkelo
Copy link
Member

torkelo commented Feb 3, 2016

Sounds like a good feature to have in Grafana. Would like help with PR as there is so much other stuff that is really high priority right now

@torkelo torkelo reopened this Feb 3, 2016
@torkelo torkelo added area/auth type/feature-request prio/medium Important over the long term, but may not be staffed and/or may need multiple releases to complete. help wanted labels Feb 3, 2016
@german-bortoli
Copy link
Author

Nice explanation @adamlwgriffiths the same thing happens to me.

Right now We solved this issue with a little hack, adding a javascript that automatic login to grafana, but is a temporal solution

@comcomservices
Copy link

+10 for this!!
To make this secure there should be a hash of the username + password + date, contained in the token. This could be used to expire the token after x number of hours to improve security.

If I get some time I'll seriously consider working on this

@adamlwgriffiths
Copy link

If you're storing the date of the token's creation so you can expire it, then you're also storing the hash and the associated account, so I don't think the hash needs to be generated from any particular data. It just needs to be a sufficiently large enough search space to make guessing infeasible.

@comcomservices
Copy link

@adamlwgriffiths, this should support some basic roles aswell.. such as viewer, editor.. etc, similar to what is done with the API keys.. Perhaps we could just extend that so we could pass an api key in via url?

@adamlwgriffiths
Copy link

I think - in the long term - the user / org / api token needs to be consolidated, rather than a new method added.
If the API tokens were expanded to allow use from the HTML interface then this wouldn't be a problem.
The API tokens already have roles, and can be revoked, so it just needs to be usable for the web view rather than pure API.

IMO API tokens should work the same as normal users. There's an arbitrary segregation that isn't documented and I find to be counter-intuitive. Enabling all the login checks to also check for API keys would be the best I think.

@krishnakanthpps
Copy link

Has this feature been implemented? I was trying to have a user automatically get redirected to the grafana dashboard from my site..

@adamlwgriffiths
Copy link

@comcomservices As a follow-up on the token itself, you definitely could encrypt information inside the token with the user id, and the token expiring time. That way you can just read the token itself and get the information without requiring tokens to be stored in the db and running 'sweep and clear' over old tokens.

I am hesitant to recommend such a thing, I firmly believe that cryptography is hard, and without a full understanding of what you are doing, it's not a good idea to attempt to do it.

The other issue with encrypted tokens, is that they are rather large, and the more information the larger they become.
Where as a random string can be made to any length, as long as the space is large enough to make brute force infeasible.

@comcomservices
Copy link

@adamlwgriffiths as far as cryptography goes, I have a formal background in it and enjoy it but for this case I'm in full agreement that a token would be best.. Just trying to figure out this go stuff, been doing c++ and asm for way too long... I'll get it though and this is first on my list

@rca
Copy link

rca commented Mar 24, 2016

I'm looking forward to this feature! Regarding @adamlwgriffiths comment above with respect to embedding the token on a site, I believe the way to mitigate that is associating that token with a domain that should be requesting it; that way that token only works when the origin matches. An example of this -- again, if I understand the issue correctly -- is Sentry's raven-js; it will make a public URL and then restrict it by origin (see below). Would this mitigate the security concern?

screen shot 2016-03-24 at 10 57 18 am

@rca
Copy link

rca commented Mar 25, 2016

@Germanaz0 is your auto-login JS publicly available? I'm looking to implement something similar against the master branch and it appears that the backend redirects to the login screen prior to hitting the dashboard page. I'm not super familiar with the project structure yet, so I may not be plugging into the right section in the JS code.

@german-bortoli
Copy link
Author

german-bortoli commented Mar 25, 2016

@rca yes, but my solution is super simple https://gist.github.com/german-bortoli/d41b5f60dd8097405b6b

You receive an input parameter like ?t=base64 of a json with {user: USERNAME, pass: PASS, redirect_to: _URL_TO_REDIRECT }

You shall include that script into the login page.

@rca
Copy link

rca commented Mar 25, 2016

@Germanaz0, thanks for sharing! After sending my comment I started taking a look and, as you pointed out, I found that I needed to update the login page. I took a slightly different approach and updated the login controller instead of making a stand-alone script; my change is here: https://github.com/zymbit/grafana/tree/auto-login-by-cookie-redirect

Is this worthy of a pull request? I'd be happy to make the mods necessary to get this into a merge'able state.

@klausenbusk
Copy link
Contributor

Any update on this?
@rca Did you create a PR?

@megastef
Copy link

megastef commented Oct 1, 2016

+1 for a PR from @rca

@scottfuhrman
Copy link

@Germanaz0, which file are you including your .js file in?

@scottfuhrman
Copy link

@rca do you have any instructions on how to use your login controller mod? i am new to grafana and trying to get this working for an unattended kiosk.

@scottfuhrman
Copy link

BTW if anyone else needs a way to accomplish this for kiosk's, etc., chek out Grafana's authproxy. I was able to accomplish what I needed to with this and apache.

@rca
Copy link

rca commented Dec 14, 2016

@scottfuhrman Nothing formally written, however, here's my usecase and implementation:

I wasn't looking for kiosk mode, but rather a way to embed a dashboard as an iframe on an external page. The charts are embedded pretty clean, for example:

screen shot 2016-12-14 at 10 24 06 am

On the page you're looking to embed the dashboard, you need the following markup:

<div id='grafana-dashboard' class="col-lg-12"></div>


<script type="text/javascript">
    GrafanaEmbed = {
        grafanaUrl: 'https://your.grafana.example.com',
        dashboard: 'dashboad-name',
        queryParams: {
            dashnav: 0,
            // this is a base64-encoded string of username:password
            // for example on a *NIX machine (and Mac OS X):
            // $ echo "kiosk1:supersecret" | base64
            // a2lvc2sxOnN1cGVyc2VjcmV0Cg==
            auth: 'a2lvc2sxOnN1cGVyc2VjcmV0Cg==',
            theme: 'light'
        }
    };

    (function() {
        var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
        d.src = GrafanaEmbed.grafanaUrl + '/public/app/features/dashboard/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
    })();
</script>

Hope this helps.

@vpetersson
Copy link

+1

I don't have the staffing resources for this, but I'd be happy to crowdfund the effort for this.

@wemod123
Copy link

wemod123 commented Feb 3, 2021

Is there any possible in future this feature will be officially support natively by Grafana?

Or if there are some consideration the team is not desired to have this feature for some reason, and definitely will not implement,
Then help to make a decision to proceed solutions.

@ivanpiffer
Copy link

so ... how to share an iframe without a user/password request page? No way ?
I wanna give the iframe code to the "webmaster" to build a simple site ... but absolutely I dont understand if is possible.

@kaoushtuv
Copy link

@rca yes, but my solution is super simple https://gist.github.com/Germanaz0/d41b5f60dd8097405b6b

You receive an input parameter like ?t=base64 of a json with {user: USERNAME, pass: PASS, redirect_to: _URL_TO_REDIRECT }

You shall include that script into the login page.

I think this link is not accessible now.

@german-bortoli
Copy link
Author

https://gist.github.com/Germanaz0/d41b5f60dd8097405b6b

Sorry, the actual link is this one https://gist.github.com/german-bortoli/d41b5f60dd8097405b6b (my username was changed)

@kodeine
Copy link

kodeine commented Aug 10, 2021

any updates on this? its a good feature, i wonder why its taking ages for this feature.

@rodehoed
Copy link

Our use-case: We want to show our boards on our signage screens. Security is not an issue in this case because the url will not be shown on the screens. This missing feature keeps us from using Grafana more widely.

In the past we used https://:@grafanaurl.com but this stopped working ages ago.

Other problem is that we are using the hosted version of Grafana where we cannot proxy anything to or do other nasty tricks.

@rahulkumarprasad
Copy link

Managed to do this with success using Grafana's auth.proxy and Nginx's ngx_http_secure_link_module
The links I use are in the format http://grafana/?user=nayar&md5=2tutcea9nfdsfdsfdsw&expires=1505386800
Once the user clicks on it, the session cookie is set and the user can browse grafana as if he logged in normally.
Advantages:

  • Link expires after some time + security
  • Link generates hash with userid, timestamp and passkey + security
  • No need to type in password + convenience

My nginx conf is like this

server {
	listen 3001 default_server;
# 	listen [::]:3001 default_server;

	server_name _;
	
        location / {
		set $user "";
		set $state "";
		
		if ($args ~ "^user=(.+)&md5") {
                    set $user $1;
                    set $state "${state}U";
                }
		
		secure_link $arg_md5,$arg_expires;
                secure_link_md5 "$secure_link_expires$uri$user grafanarocks";
                
                if ($secure_link = "") { 
                    set $state "${state}S1";
                }
                
                if ($secure_link = "0") { 
                    set $state "${state}S2";
                }
                
                add_header X-uristate "$state";

                if ($state = "US1") { return 403; }
                if ($state = "US2") { return 410; }
                
                add_header X-uri "$user";

                proxy_set_header X-WEBAUTH-USER $user;

                proxy_pass http://127.0.0.1:3000;
            }
    }

Feel free to contact me if you need help with this

This solution doesn't work for me. Because I think each request should contain valid X-WEBAUTH-USER header. It doesn't work if you fill the header on the first request, get cookies and go with them.

I ended with the next solution:

server {
  listen 80 default_server;
  listen [::]:80 default_server;

  client_max_body_size 10m;
  root /foo/public;

  location /grafana/ {
    auth_request /gauth;
    auth_request_set $user $upstream_http_user;

    proxy_set_header X-WEBAUTH-USER $user;
    proxy_pass http://localhost:4000/;
  }

  location / {
    try_files $uri @app;
  }

  location @app {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-SSL-Client-Cert $ssl_client_cert;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_redirect  off;
  }
}

So the solution uses auth_request nginx module. My app is responsible for access control (/gauth request) and returns username in User response header.

@kkolotyuk

hi sir, i am new to grafana and i have tried nginx method of auto-login that you have mentioned above but it is not working for me can you please help me in this.

@prateeksarda
Copy link

If you're using oauth there's a way to pull off an embedded grafana without a double login

  1. Setup grafana with a single oauth provider and no other login mechanisms
  2. Set GF_AUTH_OAUTH_AUTO_LOGIN to true
  3. Host grafana at a subpath and use a reverse proxy so that grafana is served at the same host as your main app
  4. Hook your main app and grafana to the same oauth provider (to the oauth provider they will be the same "app")
  5. Embed grafana
  6. When the iframe loads, grafana will try to login automatically with oauth (which should succeed since its at the same domain as your main app, thus sharing the same auth cookie)

EDIT: You may need to set security.cookie_samesite=none in grafana for this to work correctly in some browsers (This is because in the iframe, a redirect to the oauth provider (different domain) is happening and then a redirect back to your grafana domain. Currently, firefox will not allow a samesite cookie set to lax to persist in this way. https://bugzilla.mozilla.org/show_bug.cgi?id=1454027 which means grafana looses its oauth_state cookie if cookie_samesite is not set to none)

I tried this and have KeyCloak as my OAuth provider for both my app and Grafana (same client id)

with my grafana.ini

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

[auth]
disable_login_form= true
oauth_auto_login= true

[security]
cookie_samesite: none
allow_embedding: true
cookie_secure: false

[auth.generic_oauth]
enabled= true
client_id= my-app
scopes= "openid profile email"
empty_scopes= false
auth_url= "http://k3u-keycloak:5557/auth/realms/master/protocol/openid-connect/auth"
token_url= "http://k3u-keycloak:5557/auth/realms/master/protocol/openid-connect/token"
api_url= "http://k3u-keycloak:5557/auth/realms/master/protocol/openid-connect/userinfo"
allow_sign_up= true
name= KeyCloak

But that doesnt work with embedded iframe loading Grafana
What am I missing?

@laundmo
Copy link

laundmo commented Nov 10, 2021

@prateeksarda this js just a complete shot in the dark: can you see if the oauth cookies are set when visiting grafana? this method seems to reoy on cookies, and its possible that somehow your oauth provider doesn't set them in a way they stick around inside iframes?

@prateeksarda
Copy link

prateeksarda commented Nov 10, 2021

@prateeksarda this js just a complete shot in the dark: can you see if the oauth cookies are set when visiting grafana? this method seems to reoy on cookies, and its possible that somehow your oauth provider doesn't set them in a way they stick around inside iframes?

@laundmo Grafana individually sets the oauth_state cookie and grafana_session cookie but somehow in iframe when it loads Grafana it only creates it has oauth_state cookie but not grafana_session

@rezab777
Copy link

rezab777 commented Nov 17, 2021

This is my nginx config and it successfully authenticates automatically. But the issue here is there is no restriction, meaning, anyone with a link to the grafana endpoint will be authenticated. How is that different from opening up anonymous auth ?
How can authentication be restircted to the origin where a dashboard is being embedded or if the request if coming from a specific IP ?

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80;
        server_name  _;
    return 301 https://$host$request_uri;
    }

# Settings for a TLS enabled server.
#
    server {
        listen       443 ssl http2;
        listen       [::]:443 ssl http2;
        server_name  grafana.webapp.com;
        root         /usr/share/nginx/html;
#
        ssl_certificate "/etc/letsencrypt/live/grafana.webapp.com/fullchain.pem";
        ssl_certificate_key "/etc/letsencrypt/live/grafana.webapp.com/privkey.pem";
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_prefer_server_ciphers on;
    
    location / {
                set $grafana_user "admin";
                add_header Content-Security-Policy "frame-ancestors admin.webapp.com";
                add_header X-Frame-Options "ALLOW-FROM admin.webapp.com";
                proxy_pass http://localhost:3000;
                proxy_set_header X-WEBAUTH-USER $grafana_user;
                proxy_set_header Authorization "";
                     
    }


}
}

@tiagorg-cit
Copy link

@rezab777 you found any solution? I'm trying and stopped in the same point...

@rezab777
Copy link

rezab777 commented Dec 28, 2021

@tiagorg-cit
I settled with HTTP basic auth and IP restriction

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80;
        server_name  _;
	return 301 https://$host$request_uri;
    }

# Settings for a TLS enabled server.
#
    server {
        listen       443 ssl http2;
        listen       [::]:443 ssl http2;
        server_name  grafana.server.com;
        root         /usr/share/nginx/html;
#
        ssl_certificate "/etc/letsencrypt/live/grafana.server.com/fullchain.pem";
        ssl_certificate_key "/etc/letsencrypt/live/grafana.server.com/privkey.pem";
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_prefer_server_ciphers on;
	location / {
	satisfy any; # this means when either of these rules apply, do not enable HTTP basic auth.
	allow 10.255.255.255/32;
	allow 10.255.255.255/32;
	allow 10.255.255.255/32; 
        # you can add other IPs as needed
	deny all; # this means deny request from all other IPs
	auth_basic "Restricted";
	auth_basic_user_file /etc/nginx/.htpasswd; 
	proxy_http_version 1.1;
	proxy_set_header Upgrade $http_upgrade;
	proxy_set_header Connection "Upgrade";
	proxy_set_header Host $http_host;
	proxy_pass http://localhost:3000;
	proxy_set_header Authorization "";
	}

}
}

To enable HTTP basic auth in NGINX
https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/

@tiagorg-cit
Copy link

@tiagorg-cit I settled with HTTP basic auth and IP restriction

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80;
        server_name  _;
	return 301 https://$host$request_uri;
    }

# Settings for a TLS enabled server.
#
    server {
        listen       443 ssl http2;
        listen       [::]:443 ssl http2;
        server_name  grafana.server.com;
        root         /usr/share/nginx/html;
#
        ssl_certificate "/etc/letsencrypt/live/grafana.server.com/fullchain.pem";
        ssl_certificate_key "/etc/letsencrypt/live/grafana.server.com/privkey.pem";
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_prefer_server_ciphers on;
	location / {
	satisfy any; # this means when either of these rules apply, do not enable HTTP basic auth.
	allow 10.255.255.255/32;
	allow 10.255.255.255/32;
	allow 10.255.255.255/32; 
        # you can add other IPs as needed
	deny all; # this means deny request from all other IPs
	auth_basic "Restricted";
	auth_basic_user_file /etc/nginx/.htpasswd; 
	proxy_http_version 1.1;
	proxy_set_header Upgrade $http_upgrade;
	proxy_set_header Connection "Upgrade";
	proxy_set_header Host $http_host;
	proxy_pass http://localhost:3000;
	proxy_set_header Authorization "";
	}

}
}

To enable HTTP basic auth in NGINX https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/

Nice @rezab777 , this grafana/nginx is open to the internet with ip restriction, or this infrastructure is private?

@gowrisankar22
Copy link

gowrisankar22 commented Jan 19, 2022

Hi All,
I tried with auth proxy + apache for the automatic login, https://grafana.com/docs/grafana/latest/auth/auth-proxy/
example: http://admin:admin@localhost in the browser, i see that it is logged in with error Dashboard init failed and once i do the refresh error is gone. Any idea what i am missing here, to fix it in the first run itself ?

grafana.ini

[auth.basic]
enabled = true

[auth.proxy]
enabled = true
header_name = X-WEBAUTH-USER
header_property = username
auto_sign_up = true
enable_login_token = true
root_url = /

[security]
allow_embedding = true
cookie_samesite = none


httpd.conf

ServerRoot "/usr/local/apache2"
Listen 80
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
<IfModule unixd_module>
User daemon
Group daemon
</IfModule>
ServerAdmin you@example.com
<Directory />
    AllowOverride none
    Require all denied
</Directory>
DocumentRoot "/usr/local/apache2/htdocs"
ErrorLog /proc/self/fd/2
LogLevel error
<IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common
    <IfModule logio_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>
    CustomLog /proc/self/fd/1 common
</IfModule>
<Proxy *>
    AuthType Basic
    AuthName GrafanaAuthProxy
    AuthBasicProvider file
    AuthUserFile /tmp/htpasswd
    Require valid-user
    RewriteEngine On
    RewriteRule .* - [E=PROXY_USER:%{LA-U:REMOTE_USER},NS]
    RequestHeader set X-WEBAUTH-USER "%{PROXY_USER}e"
</Proxy>
RequestHeader unset Authorization
ProxyRequests Off
ProxyPass / http://grafana:3000/
ProxyPassReverse / http://grafana:3000/


@WereCatf
Copy link

I was just wanting to embed a dashboard from Grafana into an iframe, with either an API-key or username:password-combination being supplied within the URL and... well, after tussling around with it for a while, I ended up here!

My Grafana-server is publicly accessible, but I do not want random people being able to access the dashboards and I obviously don't want a login-screen in the iframe and yet it looks like Grafana doesn't have support for such a basic feature? One has to tussle around with setting up a reverse proxy with e.g. Nginx and set that up to do authentication? Seriously?

@ctonsing
Copy link

I have the same requirement. I have a web app in which I want to embed some Grafana dashboards, but I only want them to be available for users with certain roles in my app. I don't think an auth-proxy solution will work well in this case, and I don't see any other feasible options available from Grafana to achieve this. Am I missing something?

@WereCatf
Copy link

Am I missing something?

No, it does not look like you are. So far the only reasonable workaround I've found is to use Nginx with HTTP basic authentication, but that means having to duplicate usernames and passwords in .htpasswd and that quickly becomes entirely unreasonable, if one has a lot of users and/or churn.

@ctonsing
Copy link

@WereCatf, thanks for the response. Yeah, that's exactly what I thought as well, didn't want to go down that route...

@edgardmessias
Copy link

edgardmessias commented Mar 28, 2022

My solution at moment: session hijacking (Tested on chromecast)

To do that, I created a read only user and make a local authentication, after that, I copied the cookie value (grafana_session).

I added this config to my nginx server to allow to set a cookie from url:

        location /grafana/ {
                set $AC "";
                if ($arg_session) {
                    set $AC "OK";
                }
                if ($arg_session_ok = "OK") {
                    set $AC "NO";
                }
                if ($AC = "OK") {
                    add_header Set-Cookie grafana_session=$arg_session;
                    # return 301 $request_uri;
                    return 301 $scheme://$host$uri$is_args$args&session_ok=OK;
                }
                proxy_set_header Host $http_host;
                proxy_pass http://localhost:3000/;
        }

And finally, I open the link with session cookie, like: https://<url>/grafana/d/<dashid>?orgId=1&refresh=10m&kiosk=1&session=mysessionid
After load, this will redirect to : https://<url>/grafana/d/<dashid>?orgId=1&refresh=10m&kiosk=1&session=mysessionid&session_ok

For chromecast, I used this tool: https://demille.github.io/url-cast-receiver/ with location method.

@litao09h
Copy link

litao09h commented Jun 2, 2022

6 YEARS!

@vtorosyan vtorosyan assigned kalleep and unassigned alexanderzobnin Jun 7, 2022
@Jguer Jguer self-assigned this Jun 15, 2022
@Jguer
Copy link
Contributor

Jguer commented Aug 22, 2022

Closing this issue as implemented (release notes)

Using JWT authentication made sense as it's already available in Grafana, does not rely on arbitrary header values, it's signed and allows to uniquely identify a user based on an dedicated identity provider.

The URL embedding option was added as an alternative for scenarios where using a reverse proxy is not a possibility or convenient (although security wise, it might be the best option).

Official docs will follow (awaiting review here) and a sample repository is available here.

I'm sure this doesn't implement every use case presented in this thread as we focused on applications embedding grafana in iframes wanting to pass existing authentication context into grafana.

Feedback on the new feature is welcome (specially on small tweaks and documentation necessary) but if your use case is not covered by the above description, the best way to have it supported is to create a new issue and exposing the specific use case and why this approach does not work for it.

@Jguer Jguer closed this as completed Aug 22, 2022
@mateuszdrab
Copy link

Apologies for bringing this up; however, based on my understanding, the support for JWT does not mean that I can use API keys for authentication?
Right?

@kalleep
Copy link
Contributor

kalleep commented Mar 17, 2023

Hey @mateuszdrab , no atm we only support using jwt authentication through url. As mentioned here #3752 (comment), we would prefer a new issue describing your use case for using e.g. api keys through the url :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/auth help wanted prio/medium Important over the long term, but may not be staffed and/or may need multiple releases to complete. prio/unscheduled type/feature-request
Projects
No open projects
Issue preparations
  
Requirement / Discussions
Development

Successfully merging a pull request may close this issue.