Nginx auth request unexpected status 404

authentication, http-status-code-404, nginx, runtime-error

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;}

Best Solution

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 :- )