auth0/shiny-auth0

404 error with app hosted in directory other than /Reports

Opened this issue · 18 comments

I get the following 404 error when I navigate to any app that's hosted on a directory other than /Reports:

Not Found
404
Error: Not Found
    at /home/ubuntu/shiny-auth0/app.js:75:13
    at Layer.handle [as handle_request] (/home/ubuntu/shiny-auth0/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/ubuntu/shiny-auth0/node_modules/express/lib/router/index.js:317:13)
    at /home/ubuntu/shiny-auth0/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/ubuntu/shiny-auth0/node_modules/express/lib/router/index.js:335:12)
    at next (/home/ubuntu/shiny-auth0/node_modules/express/lib/router/index.js:275:10)
    at urlencodedParser (/home/ubuntu/shiny-auth0/node_modules/body-parser/lib/types/urlencoded.js:88:40)
    at Layer.handle [as handle_request] (/home/ubuntu/shiny-auth0/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/ubuntu/shiny-auth0/node_modules/express/lib/router/index.js:317:13)
    at /home/ubuntu/shiny-auth0/node_modules/express/lib/router/index.js:284:7

Any ideas?

Happy to help.
Can you share the directory structure of /srv/shiny-server/
You're on ubuntu so you can use these commands to do this:
sudo apt-get install tree
tree /srv/shiny-server/

Can you also share your shiny server config file's content? (file location: /etc/shiny-server/shiny-server.conf)

Hey Karl -

Here's what my shiny-server.conf looks like:

# Instruct Shiny Server to run applications as the user "shiny"
run_as shiny;

# Define a server that listens on port 3838
server {
  listen 3838;

  # Define a location at the base URL
  location / {

    # Host the directory of Shiny Apps stored in this directory
    site_dir /srv/shiny-server/;

    # Log all Shiny output to files in this directory
    log_dir /var/log/shiny-server;

    # When a user visits the base URL rather than a particular application,
    # an index of the applications available in this directory will be shown.
    directory_index off;
    app_init_timeout 1800;
    app_idle_timeout 86400;
  }
}

Note, I explicitly left the '127.0.0.1' off after the port declaration so I could access the app via remote. (I left port 3838 open on my EC2 instance)

Here's my directory output (with filenames removed):

/srv/shiny-server$ tree
.
└── StretchyCannulaJumpyPostwarJobber
    ├── glbl.R
    ├── google-analytics.js
    ├── helper2.R
    ├── helper.R
    ├── index.Rmd
    ├── init.R
    ├── srvr.R
    ├── styles.css
    ├── uiModules.R
    └── unzoom.js

All it is in a single directory named StretchyCannulaJumpyPostwarJobber. (That is, if you navigate to: XXXX.com:3838/StretchyCannulaJumpyPostwarJobber it loads)

Here's my nginx.conf:

events {
}

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    # Listen on port 80 and redirect all requests to the
    # TLS enabled server (https, port 443)
    server {
        listen       *:80;

        # Your hostname should go here
        server_name  XXXX.com;

        access_log   off;
        location / {
            rewrite ^ https://$host$request_uri? permanent;
        }
    }

    # TLS enabled server
    server {
        listen       443 ssl;

        # Your hostname should go here
        server_name XXXX.com;

        # TLS/SSL certificates for your secure server should go here.
        # If you don't have a TLS certificate, you can get a free one by
        # following the free PDF available in this link:
        # https://auth0.com/blog/using-https/
        ssl_certificate      /etc/letsencrypt/live/XXXX.com/fullchain.pem;
        ssl_certificate_key  /etc/letsencrypt/live/XXXX.com/privkey.pem;

        # To enhance security, as long as you don't need to support older browsers
        # (and you probably don't), you should only enable the most secure
        # ciphers and algorithms. This is a sane selection.
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GC$
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_session_cache  builtin:1000  shared:SSL:10m;
        ssl_stapling on; # Requires nginx >= 1.3.7
        ssl_stapling_verify on; # Requires nginx => 1.3.7

        # This proxies requests to our shiny-auth0 authentication proxy.
        # Requests are passed in plain HTTP, so TLS termination
        # is applied at this point.
        location / {
            proxy_set_header    Host $host;

            # This points to our shiny-auth0 authentication proxy,
            # change localhost:3000 to suit the configuration of
            # your shiny-auth0 config
            proxy_pass          http://localhost:3000;
            proxy_redirect      http://localhost:3000/ $scheme://$host/;

            proxy_http_version  1.1;

            # The following lines enable WebSockets proxying, do not remove them
            # as they are used by Shiny Server to improve user experience
            proxy_set_header    Upgrade $http_upgrade;
            proxy_set_header    Connection $connection_upgrade;

            proxy_connect_timeout 3h;
            proxy_send_timeout 3h;
            proxy_read_timeout 3h;
        }
    }
}

Lastly, here's my .env file from ~/shiny-auth0/:

AUTH0_CLIENT_SECRET=XXXX
AUTH0_CLIENT_ID=XXXX
AUTH0_DOMAIN=XXXX.auth0.com
AUTH0_CALLBACK_URL=https://XXXX.com/callback
COOKIE_SECRET=XXXX
SHINY_HOST=localhost
SHINY_PORT=3838
PORT=3000

# Auto login if the session exists on Auth0 Server
CHECK_SESSION=true
# When logout is called, log the user out of Auth0 aswell
LOGOUT_AUTH0=true
# When logging out is called, must logout of remote idp aswell
# This will force LOGOUT_AUTH0 to true
LOGOUT_FEDERATED=true

To recap, when I navigate to XXXX.com, with the above setup I am prompted by Auth0 to login -- which I do and that works. It redirects me to /reports. However, I cannot navigate to my app that're stored on /StretchyCannulaJumpyPostwarJobber as defined in my shiny-server.conf.

Lemme know if you see a glaring mistake or something missing. Much appreciated!!!

Just to get it straight,
If you navigate to XXXX.com/reports/StretchyCannulaJumpyPostwarJobber/ then it shows the 404 error?

I was going to tell you that you need to add the app to shiny-server.conf but you're using site_dir on /srv/shiny-server/ and not app_dir.
I had a problem once where the forward slash (/) at the end of the link would do this kind of issue.

Here's how:

  1. I open XXXX.com/reports/myshinyapp <-- without a forward slash
  2. I get automatically redirected after login (shiny-auth0) to XXXX.com/myshinyapp and into a 404 page. <-- Notice /reports is missing
  3. I had to type the address again in the address bar (XXXX.com**/reports/**myshinyapp/) so that I get to the app

I wouldn't have this problem at all if I typed the forward slash at the end in the beginning XXXX.com/reports/myshinyapp**/**

If this doesn't help, try moving all your app files in /srv/shiny-server and check if you encounter the same problem you stated in your first post.

Here's what's going on:

  1. I goto XXXX.com, it prompts me to login via Auth0.
  2. It redirects me to XXXX.com/reports. I don't want that.

I want it to redirect me to XXXX.com/StretchyCannulaJumpyPostwarJobber.

When I manually type the URL http://XXXX.com:3838/StretchyCannulaJumpyPostwarJobber/ in my browser, the app is accessible (given my shiny-server.conf), but shiny-auth0 is not redirecting to it properly.

I also tried making the following change to my ./shiny-auth0/routes/index.js file:

var express = require('express');
var passport = require('passport');
var httpProxy = require('http-proxy');
var ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn()
var router = express.Router();

var env = process.env;

// This adds support for the current way to sso
var authenticateWithDefaultPrompt = passport.authenticate('auth0', {});
var authenticateWithPromptNone = passport.authenticate('auth0', {
  prompt: 'none'
});


/* GET home page. */
router.get('/', function(req, res, next) {
  res.redirect('/StretchyCannulaJumpyPostwarJobber/');
});

router.get('/login',
  function (req, res, next) {
    if (env.CHECK_SESSION === 'true' && req.query.sso !== 'false') {
      return authenticateWithPromptNone(req, res, next);
    }
    return authenticateWithDefaultPrompt(req, res, next);
  },
  function (req, res) {
    res.redirect('/StretchyCannulaJumpyPostwarJobber/');
  });

router.get('/logout', function(req, res){
  var logoutUrl = env.LOGOUT_URL;

  if (env.LOGOUT_AUTH0 === 'true') {
    logoutUrl = 'https://' + env.AUTH0_DOMAIN + '/v2/logout?returnTo=' 
      + env.LOGOUT_URL + '&client_id=' + env.AUTH0_CLIENT_ID
      + (env.LOGOUT_FEDERATED === 'true'? '&federated' : '');
  }
  
  req.logout();
  res.redirect(logoutUrl);
});

router.get('/callback',
  function (req, res, next) {
    passport.authenticate('auth0', function (err, user, info) {
      if (err) {
        next(err);
      }

      if (info === 'login_required') {
        return res.redirect('/login?sso=false');
      }

      if (user) {
        return req.login(user, function (err) {
          if (err) {
            next(err);
          }
          res.redirect(req.session.returnTo || '/StretchyCannulaJumpyPostwarJobber/');
        });
      }

      next(new Error(info));
    })(req, res, next);
  });

module.exports = router;

But I still get the following on login:

image

Hello Ray,
I understand. I've had this problem before on one of my servers and it's solved now. And I had it again on another server this morning and it's also solved now.
First, reset ./shiny-auth0/routes/index.js to what it was before the modifications that you mentioned in your last post
Please answer these questions to help you diagnose the issue accurately:

  • If you navigate to XXXX.com/reports/StretchyCannulaJumpyPostwarJobber/ does it show the Not Found error?

  • Copy all your app files from /srv/shiny-server/StretchyCannulaJumpyPostwarJobber/ to /srv/shiny-server/ and check if you get a Not Found error.

I understand you want it to redirect to XXXX.com/StretchyCannulaJumpyPostwarJobber. The above questions are just to diagnose what's causing this problem.

Hey Karl -

Again, thanks so much for your help. I reverted the changes in my routes/index.js file per your instructions and here's what's happening now:

  • When I goto XXXX.com, it prompts me to log into Auth0. I do that, and it redirects me to https://XXXX.com/reports/ and I get the following error:

image

  • However, when I manually type in https://XXXX.com/reports/StretchyCannulaJumpyPostwarJobber/ (Note, the / at the end of the URL), it works!!
  • However, if I type in https://XXXX.com/reports/StretchyCannulaJumpyPostwarJobber (WITHOUT the / at the end), it redirects me to https://XXXX.com/StretchyCannulaJumpyPostwarJobber/, and I get a different 404:

image

  • When I moved the entire app into the parent directory, /srv/shiny-server/, I get redirected to XXXX.com/reports/ which loads fine. Obviously, I want to change the URL from /reports/ to /my-app/ or anything else.

Hopefully this clarifies. Lemme know your thoughts. Much appreciated!!

@karl-j Hey Karl -- sorry to be a bother, but did you get a chance to review the above? Please let me know. Thanks!!

@iamraybao may I ask if you have found solution for your problem? I need similar solution. even more I want different users access different shiny apps.

I'm having the same issue as well.

Having the / at the end changes everything, but where do I set this?

I'm just using the sample-apps shiny server provided. I'm not even adding my own apps just yet

I am getting this error:

Not Found
404
Error: Not Found
    at /home/shiny/shiny-auth0/app.js:66:13
    at Layer.handle [as handle_request] (/home/shiny/shiny-auth0/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/shiny/shiny-auth0/node_modules/express/lib/router/index.js:317:13)
    at /home/shiny/shiny-auth0/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/shiny/shiny-auth0/node_modules/express/lib/router/index.js:335:12)
    at next (/home/shiny/shiny-auth0/node_modules/express/lib/router/index.js:275:10)
    at urlencodedParser (/home/shiny/shiny-auth0/node_modules/body-parser/lib/types/urlencoded.js:88:40)
    at Layer.handle [as handle_request] (/home/shiny/shiny-auth0/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/shiny/shiny-auth0/node_modules/express/lib/router/index.js:317:13)
    at /home/shiny/shiny-auth0/node_modules/express/lib/router/index.js:284:7

I am able to set all of the variables correctly, but the 404 error keeps showing up. I have not installed any new apps either. I followed this tutorial, but the 404 is very persistent: https://www.r-bloggers.com/shiny-server-series-part-4-adding-user-authentication-using-auth0/

Did you ever get this working properly? I'm having this exact problem.

I would like to have an explanation for that. Its nearly the same problem. To sum up:

When I access the auth0 proxy via domain:3838 it presents me the auth0 login screen.
If I enter domain/shiny I get "Page not found" and rewrites the url to domain/reports

I configured my nginx "location /shiny/" like that the server will rederict every traffic coming from this site to the auth0 proxy.

Can please someone explain what that "reports.js" and "/reports/" url is supposed to do?

How should one store the apps in the shiny-server/ folder?

Thank you guys

Anyone figure this out, experiencing the same issue
Thanks!

Hey everyone, I think I came up with a solution.

@iamraybao Almost had it. The extra needed step is to edit app.js. From his example, you need to edit app.js from this:

app.use('/reports/', reports);
app.use('/', routes);

to this

app.use('/StretchyCannulaJumpyPostwarJobber/', reports);
app.use('/', routes);

And also edit index.js like he did, replacing all references to /reports/ to the path you would like.

-JW

Anyone figure this out, experiencing the same issue
Thanks!

YO-SC commented

Anyone found out a solution yet ? I have this same issue.

Thanks

YO-SC commented

Hey everyone, I think I came up with a solution.

@iamraybao Almost had it. The extra needed step is to edit app.js. From his example, you need to edit app.js from this:

app.use('/reports/', reports);
app.use('/', routes);

to this

app.use('/StretchyCannulaJumpyPostwarJobber/', reports);
app.use('/', routes);

And also edit index.js like he did, replacing all references to /reports/ to the path you would like.

-JW

This kinda helps, but it still brings a "Page not found" error.

Hi all, I think there seems to be 2 issues here, both related to the urls that this auth0 app is proxying to the Shiny server:

  • the app is proxying the shiny-server apps at the "reports/" endpoint. So you can access the /srv/shiny-server/StretchyCannulaJumpyPostwarJobber app at http://XXXX.com/reports/StretchyCannulaJumpyPostwarJobber/, which is not what you might expect if you're used to shiny servers without this auth0 app.
  • the issue @iamraybao references above about the redirect that happens if you miss out the last "/" in the url seems to be something to do with how this app recognises which urls should be sent to the Shiny proxy.

The solution that seems to work for me is to add another app.use() call just before the 404 error is thrown (app.js line 74-78). The function attempts to redirect the user to the "reports/" endpoint. So if a user asks for http://example.com/appName, they reach http://example.com/reports/appName/, which loads the Shiny app inside /srv/shiny-server/appName.

app.use(function(req, res, next) {
  res.redirect('/reports'+req.url);
});

This is only called if the user's request hasn't already been handled by the "reports" or "index" modules, so it doesn't interfere with any of the proxying or authentication stuff. It seems to fix both issues for me, so now users can reach the shiny app at any of the following urls (using the original app name as example):

  • http://XXXX.com/StretchyCannulaJumpyPostwarJobber
  • http://XXXX.com/StretchyCannulaJumpyPostwarJobber/
  • http://XXXX.com/reports/StretchyCannulaJumpyPostwarJobber
  • http://XXXX.com/reports/StretchyCannulaJumpyPostwarJobber/

...and of course, this works when you replace the app name with any folder name inside your /srv/shiny-server folder.

(edit - note this doesn't actually solve the underlying issue, as http://XXXX.com/StretchyCannulaJumpyPostwarJobber will still redirect you and add the "reports/" bit to the url! So if you want totally clean urls I think you'll need to dive into changing how this app is proxying the Shiny server... but this solution should at least make it easier for your users to find your Shiny apps!)

Hope this helps!