/Authorization route does not work with website hosted behind IIS reverse proxy. Only localhost:port works

here is a proper authorize link that I get when using Node.js express application via localhost:3067/login:

https:// dev-wg2ioezy8v4cunjl.us.auth0.com/u/login?state=hKFo2SBjRFo0dGxNQ190UlJQUGl4TGdacDFBVXFGMXhNZENDbaFur3VuaXZlcnNhbC1sb2dpbqN0aWTZIGV0UTFnWWJNQW9JOG00SWQ4bjVaalZDZk9RRWJENWxvo2NpZNkgb1BxcVRTSDRiNmszRmxaR1pxZEl0VjJLQlZQVlIzdzg

        and then after login directs me to https://localhost:3067/welcome. Here is what we're trying to get working. only works fine on https://localhost:3067 but the second you use the IIS reverse proxy to access the website via testing.dupps.com then the authorization route does not work. I've tried the default downloadable Node.js applicaiton code that auth0 provides and created my own custom as well in the 2nd code snippet, but no luck the second I use the reverse proxy. 
const dotenv = require('dotenv');
const express = require('express');
const https = require('https');
const logger = require('morgan');
const path = require('path');
const fs = require('fs');
const { auth, requiresAuth } = require('express-openid-connect');
const session = require('express-session');  // Require express-session

dotenv.config();

const app = express();

app.set('trust proxy', 'loopback, linklocal, uniquelocal');
app.set('trust proxy', true);


app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());

// Configure express-session middleware
app.use(session({
  secret: 'yourSecretKey',
  resave: false,
  saveUninitialized: false,
  cookie: { secure: true, sameSite: 'none' }  // Adjust for cross-domain auth
}));

app.use((req, res, next) => {
  console.log('Headers:', req.headers);
  next();
});



const config = {
  authRequired: false,
  auth0Logout: true,
  secret: '',
  baseURL: process.env.BASE_URL || 'https://testing.dupps.com',  // Use env var for production URL
  clientID: 'oPqqTSH4b6k3FlZGZqdItV2KBVPVR3w8',
  issuerBaseURL: 'https://dev-wg2ioezy8v4cunjl.us.auth0.com',
  authorizationParams: {
    redirect_uri: 'https://testing.dupps.com/callback'
  }
};

const port = process.env.PORT || 3067;
if (!config.baseURL && !process.env.BASE_URL && process.env.PORT && process.env.NODE_ENV !== 'production') {
  config.baseURL = `https://testing.dupps.com`; // Change this to the reverse proxy URL
}

app.use(auth(config));

// Middleware to make the `user` object available for all views
app.use(function (req, res, next) {
  res.locals.user = req.oidc.user;
  res.locals.isAuthenticated = req.oidc.isAuthenticated();
  next();
});

// Routes (integrated from router)
app.get('/', function (req, res, next) {
  const cookieEnabled = req.headers.cookie ? true : false;
  res.render('index', {
    title: 'Auth0 Webapp sample Nodejs',
    isAuthenticated: req.oidc.isAuthenticated(),
    cookieEnabled: cookieEnabled
  });
});


app.get('/profile', requiresAuth(), function (req, res, next) {
  res.render('profile', {
    userProfile: JSON.stringify(req.oidc.user, null, 2),
    title: 'Profile page'
  });
});

// Route to initiate Auth0 login
app.get('/authorize', (req, res) => {
  console.log("Redirecting to Auth0...");
  res.redirect(
    `${process.env.ISSUER_BASE_URL}/authorize?client_id=${process.env.CLIENT_ID}&scope=openid%20profile%20email&response_type=id_token&redirect_uri=${encodeURIComponent(process.env.BASE_URL + '/callback')}&response_mode=form_post&nonce=${req.query.nonce}&state=${req.query.state}`
  );
});

// Route to handle Auth0 callback
app.post('/callback', express.urlencoded({ extended: false }), (req, res) => {
  console.log("Received callback from Auth0:", req.body);
  
  const { id_token } = req.body;
  if (!id_token) {
    return res.status(400).send('Authentication failed');
  }
  
  // Store user session
  req.session.user = id_token;
  
  // Redirect to home or dashboard
  res.redirect('/');
});




// Catch 404 and forward to error handler
app.use(function (req, res, next) {
  const err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// Error handlers
app.use((err, req, res, next) => {
  console.error('Error:', err);
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: process.env.NODE_ENV !== 'production' ? err : {}
  });
});


// Path to your PFX file and passphrase if needed
const pfxPath = path.join(__dirname, 'key.pfx'); // Adjust the path accordingly
const passphrase = ''; // Change this to your actual passphrase

// Create HTTPS options with PFX certificate
const httpsOptions = {
  pfx: fs.readFileSync(pfxPath),
  passphrase: passphrase // If there's no passphrase, you can omit this
};

// Start the HTTPS server
https.createServer(httpsOptions, app)
  .listen(port, () => {
    console.log(`Listening securely on ${config.baseURL}`);
  });

and here is the custom Node.js app I made:

const dotenv = require('dotenv');
const express = require('express');
const https = require('https');
const path = require('path');
const fs = require('fs');
const session = require('express-session');
const { auth } = require('express-openid-connect');

// Load environment variables
dotenv.config();

const app = express();

// Set up view engine
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));

// Session configuration
app.use(session({
  secret: process.env.SECRET,
  resave: false,
  saveUninitialized: true,
  cookie: { 
    secure: true,
    maxAge: 24 * 60 * 60 * 1000 // 24 hours
  }
}));

// SSL certificate options
// Note: For production, you should use proper SSL certificates
// For development, you can generate self-signed certificates
const pfxPath = path.join(__dirname, 'key.pfx'); // Adjust the path accordingly
const passphrase = '1234'; // Change this to your actual passphrase

// Create HTTPS options with PFX certificate
const httpsOptions = {
  pfx: fs.readFileSync(pfxPath),
  passphrase: passphrase // If there's no passphrase, you can omit this
};


// Auth0 configuration
const config = {
  authRequired: false,
  auth0Logout: true,
  baseURL: `https://localhost:${process.env.PORT}`,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
  secret: process.env.SECRET,
  clientSecret: process.env.SECRET, // Added client secret
  authorizationParams: {
    response_type: 'code',
    scope: 'openid profile email'
  },
  routes: {
    login: '/login',
    callback: '/callback',
    postLogoutRedirect: '/'
  },
  session: {
    rollingDuration: 60 * 60 * 24, // 24 hours in seconds
    absoluteDuration: 60 * 60 * 24 * 7, // 7 days in seconds
    cookie: {
      sameSite: 'Lax'
    }
  }
};

// Auth router
app.use(auth(config));

// Make user info available to all views
app.use((req, res, next) => {
  res.locals.user = req.oidc.user;
  res.locals.isAuthenticated = req.oidc.isAuthenticated();
  next();
});

// Routes
app.get('/', (req, res) => {
  if (req.oidc.isAuthenticated()) {
    return res.redirect('/welcome');
  }
  res.render('index', { title: 'Home' });
});

app.get('/welcome', (req, res) => {
  if (!req.oidc.isAuthenticated()) {
    return res.redirect('/login');
  }
  
  const user = req.oidc.user;
  res.render('welcome', { 
    title: 'Welcome',
    user: user
  });
});

// Create HTTPS server
const server = https.createServer(httpsOptions, app);

// Start server
const PORT = process.env.PORT || 3067;
server.listen(PORT, () => {
  console.log(`Server running on https://localhost:${PORT}`);
});

Hi @jpielage2,

Welcome to the Auth Community!

I’ve taken a look into your tenant.

The reverse proxy needs to be configured so it goes to the canonical domain you have in Auth0: dev-…us.auth0.com instead of testing.dupps.com

Regarding the “test website” since there is no custom domain configured on Auth0 (https://testing.dupps.com), you need to replace it with the canonical domain from Auth0.

I will provide the Auth0 documentation for custom domain: Custom Domains

If you have any other question feel free to let us know.

Have a good one,
Vlad

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