Hitting Security API Endpoint

A little preface: I'm trying to set up the following:

Kibana: Shared dashboard with index pattern of Index-*
Site A : Embedded iframe Kibana Dashboard (with only access to Index-A)
Site B : Embedded iframe Kibana Dashboard (with only access to Index-B)
Site C : Embedded iframe Kibana Dashboard (with only access to Index-C)

Each site will have its own set of login credentials to Kibana. I've browsed the forums and come across a solution that seems to do what we're needing, but it seems the endpoint doesn't exist. I'm not sure if I don't have something turned on or if this was deprecated.

Here's what I'm trying from Postman:
POST http://localhost:5601/api/security/v1/login

(note: http://localhost:5601 is where I go to log into my local kibana site)
kbn-version: 7.8.0
Content-Type: application/json

    "password": "MYPASSWORDHERE",
    "username": "elastic"

I get the following in a response:

    "statusCode": 404,
    "error": "Not Found",
    "message": "Not Found"

I've referenced the following, but I'm clearly missing something that these posts aren't telling me. Can someone point me in the right direction?:

Any thoughts on this one? Am I completely off the mark here?

Welp. Apparently this was deprecated.


Cool. I'll look for another way to do this

Turns out that reverse proxy solution also only works if the Auth header is static so that actually doesn't work for this scenario either.

Is there any way to do what I'm looking for without having to have the user login? api key on the URL? pre-flight request to get a cookie that doesn't expire for 24 hours? Anything?

Here's where I'm at now..

Can't do:

  • Call /api/security/v1/login because it doesn't exist anymore I believe it was changed to /internal/security/login
  • Call /internal/security/login because of a CORS issue we can't rectify because of https://github.com/elastic/kibana/issues/16714#issuecomment-610715294
  • Use a reverse proxy to send the credentials because that will only work with a static set of credentials. Passing the credentials via query string and then parsing them out into an Auth header will only work for the first request, not all subsequent ones.
  • Trying this out on Elastic Cloud because it doesn't seem like that will make any difference at all for CORS. The only CORS functionality I'm seeing to configure is for Elasticsearch, not Kibana

Might work:

  • Modifying the Kibana login page to get data from its hosted page. Kibana dashboard URL will be hosting in an iframe, the Kibana login page will call out to the parent and get the credentials from a function, put the credentials into the login fields and submit.
    • The problem here is now I have to go learn React...
    • The other problem is that between versions, I'm sure these pages will also change, but I really have nothing else to go on.

This would be so much easier if I could just get the cookie instead of having to do all of this...

I am not sure how else you could accomplish this other than using a proxy at this time until we have anonymous access.

You mentioned that is not possible in this scenario. Why is that? You should be able to inject a different authorization header based on the path or some factor to account for these different instances.

It falls apart on subsequent requests. If I pass in, say the base64 encoded username and password in the query string and have it put that in the header then it will only work for that first request that has it. This lines up with what I've read about it being stateless. I've gotten it to work just fine if I manually specify the username and password in the configuration both in IIS and NGinX, but neither of them I could get to work if I needed to keep passing the username and password over and over and over to kibana.

If it at least gave me a cookie then I'd be in business.

What I'm doing now is going to try and AJAX call to a proxy. I will capture the OPTIONS call that the browser makes to validate CORS, return a response with the header Access-Control-Allow-Origin = * and 200 OK. The browser should then be able to make a call to /internal/security/login normally through the proxy and get the cookie I need to be "logged in" and it should be business as usual. If it works this way I'll post what I did to help others because this was kind of a pain.

Alright, I got something to work. I'm probably not going to list out every single step I did, but I found an IIS solution that worked for me. Sorry if you use Apache or NGinX. I'm not familiar with those web servers so I can't help there.

You must have a valid SSL Cert for IIS and IIS must be installed on the same server that your ELK stack is installed on. You may be able to spin up a free trial of this on an Azure VM and use Let's Encrypt to get an SSL Cert (or perhaps Azure has a way to let you get an SSL cert on the cheap from the portal).

OS: Windows Server 2019
Roles: Web Server (IIS)
IIS Component to install: URL Rewrite (latest version, mine reports 2.5)

The idea here is that you'll need a Reverse Proxy between the user browsing your site and Kibana. The Reverse proxy will be in charge of lying to your browser, telling it that the CORS request is valid. We have to do this because Kibana seemingly doesn't have CORS functionality exposed even though it's in the code from what I've seen on GitHub. That's why this question exists in the first place.

I can post my basic setup and if anyone has any questions I'll try to field them if I have a chance.

This is the page that will host the embeded dashboard. You'll have to pass the username and password somehow to the user. If you can figure out some process to encrypt it I suppose, but it really makes no difference because either way the user will have the cookie when they are logged in.
index.html code:

    var raw = JSON.stringify({ "username": "omittedusername", "password": "omittedpassword" });
    var iframeSource = "https://my-elk-proxy.com/app/kibana#/dashboard/e0eaa645-decd-45d9-b166-274c89374b5e?embed=true&omittedparams";

    function login_success(e) {
        document.getElementById("myiframe").src = iframeSource;

    function login_error(e) {

    $.ajax("https://my-elk-proxy.com/internal/security/login", {
        method: 'POST',
        data: raw,
        crossDomain: true,
        xhrFields: {
            withCredentials: true
        beforeSend: function (xhr) {
            xhr.setRequestHeader('kbn-version', '7.8.0');
            xhr.setRequestHeader('Content-Type', 'application/json');
        success: login_success,
        error: login_error

You will need to create a site in IIS with a binding on port 443 (SSL port)

You will need to find the URL Rewite icon under the site you made and make sure the server variable HTTP_Authorization is allowed

You will need to set up both inbound and outbound rules. Both inbound rules should be set up as "Reverse Proxy" while the outbound rule should be set up as "Blank rule":

Options Intercept Rule 1 of 2

Note: The HTTP_Origin where it's blurred out is simply a regex that will match the Header "Origin" that's sent in the header. Mine was https://localhost:31345 for instance, but you can put multiple here as long as it's valid regex. This will keep sites you don't want hosting your dashboards from doing so; however, if you have multiple sites, it will not keep site A from hosting site B's content in the event that they were to get each other's credentials.

Options Intercept (same rule as above, don't save changes yet) Rule 2 of 2

General Proxy (this handles the subsequent calls after the OPTIONS call. The blurred out portion is the URL you go to for your Kibana instance)

Outbound Rule (This will make sure the cookie comes across so that future browser updates should allow this cookie to be set securely. If you don't do SameSame=None and Secure then you'll get a browser warning, but it should still work)

Edit: I forgot to add what I used for the Precondition above. It looks like this. It basically checks to see if Set-Cookie exists in the unaltered ELK response before running the rule

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.