learner
learner

Reputation: 950

Nginx auth request unexpected status 404

I am getting following error when a sub-request is sent to nginx auth_request module. For information, I have developed a spring security based web application which contains only one web method i.e. authenticate to verify user credentials and sessions and it responds with either 200 or 401 error code.

After successful authenticaiton page is redirected to the home url which shall display the home page of upstream application, instead I am getting this error in nginx logs which states as follows

Error auth request unexpected status: 404 while sending to client, client: 127.0.0.1, server: , request: "GET / HTTP/1.1", host: "localhost:8180", referrer: "https://localhost:8180/login.html"*

This error shows that nginx has passed complete requested url to auth subrequest instead of "/authenticate" and the auth service looks for the resourcse which it couldn't find in it and throws a 404 error.

    server {
    listen    8180 ssl;
    ssl_certificate         certs/nginx.pem;
    ssl_certificate_key     certs/nginx.pem;

    location /{
        proxy_set_header xclnt "ap1";  
        auth_request /authenticate;
        proxy_pass https://adi-backend;         
    }

    location = /authenticate {
        proxy_set_header xclnt "ap1";  
        proxy_pass http://authserv;
    }

    location = /login.html {
        root   html;
    }

    location = /50x.html {
        root   html;
    }
    error_page   500 502 503 504  /50x.html;
    error_page  401 403 login.html;
}

Upvotes: 4

Views: 17724

Answers (3)

Bw. Kizito
Bw. Kizito

Reputation: 178

GENERIC RESPONSE:

I wish the docs would point out that auth_request fires a GET request, I spent my six hours trying a boatload of GPT's in vain.

If in any case anyone is using a POST in the auth_request route, make sure that you change it to GET, the token in the header such as Authorization: Bearer xyz-etc work just fine in a GET request.

Upvotes: 0

ghuehjxtbohnzirjpo
ghuehjxtbohnzirjpo

Reputation: 41

It might me helpful to somebody... In my case, changing

location = /authenticate {
        proxy_set_header xclnt "ap1";  
        proxy_pass http://authserv;
    }

to

location = /authenticate {
        proxy_set_header xclnt "ap1";  
        proxy_pass http://authserv/;
    }

(slash at the end of the URL in proxy_pass) solved the issue...

Upvotes: 4

KajMagnus
KajMagnus

Reputation: 11666

The docs say that returning status 404 Not Found from http://authserv is not supported. ngx_http_auth_request_module wants 2xx, 401 or 403 only:

If the subrequest returns a 2xx response code, the access is allowed. If it returns 401 or 403, the access is denied with the corresponding error code. Any other response code returned by the subrequest is considered an error.

The people who wrote the auth module, apparently decided that 404 means that the auth endpoint itself couldn't be found, e.g. that the auth request was sent to the wrong URL. Rather than that the requested thing didn't exist.

So, if you don't want those errors in your log — use something else than the auth module. ...

... Maybe Lua? That's what I'm doing, when I want the "auth" handler to both do auth, and also check if the thing requested, exists:

Here's my Lua approach (works fine):

location ~ ^/-/u/([^/][^/]+/)(.*)$ {

  # (1. There's Nginx's http_auth_request_module module, but it handles upstream 404 Not Found
  # as an internal error. So it cannot both do auth, and check does-it-exist? at the same time.
  # 2. ngx.location.capture is synchronous, but non-blocking: the code execution stops, until
  # a response is received — but meanwhile, the nginx worker continues with other things.)
  set $publSiteId $1;
  set $hashPath $2;
  access_by_lua '
    response = ngx.location.capture("/_auth_upload/" .. ngx.var.publSiteId .. "/" .. ngx.var.hashPath)
    if response.status == 404 then
      ngx.status = 404
      ngx.say("Not found. [TyNGXFKB604]")
      return ngx.exit(ngx.OK)
    end
    if response.status == 401 or response.status == 403 then
      ngx.status = response.status
      ngx.say("Access denied. [TyNGX5KWA2]")
      return ngx.exit(ngx.OK)
    end';

  alias /opt/talkyard/uploads/public/$2;
  ... cache headers ...
}

And here's the Nginx subrequest handler:

location /_auth_upload/ {
  # Only for Nginx subrequests.
  internal;
  proxy_pass              http://app:9000/-/auth-upload/;
  proxy_pass_request_body off;
  proxy_set_header        Content-Length "";
  proxy_set_header        X-Original-URI $request_uri;
}

Full source here. I hope this helps :- )

Upvotes: 5

Related Questions