Cloudflare effecting GET requests to nginx and my Node.js server?

I have a server with docker, with a web server within a docker running behind Cloudflare. Nginx reverse proxies the subdomain to the correct port on the server, where the Node.js web server is. Everything works fine, but when I try to authenticate with Twitch, it takes me back to the web server’s login page again. It was working fine prior to proxying the subdomain behind Cloudflare. When I check the Nginx access logs, it shows that it is in fact getting the GET requests.

Access Log:

"GET /auth/twitch HTTP/2.0" 302 0 "https://<subdomain>/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53"

"GET /auth/twitch/callback?code=<callback code> HTTP/2.0" 302 46 "https://id.twitch.tv/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53"

"GET / HTTP/2.0" 304 0 "https://id.twitch.tv/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53"

I read on other forum posts that it should be an Nginx/Webserver issue, but why is this only happening when I proxy the site behind Cloudflare?

I tried changing Page Rules/WAF on Cloudflare but it didn’t help- but maybe I was doing it wrong? Also, Bot Fight Mode isn’t enabled on Cloudflare.

(I am somewhat new to DNS/Cloudflare/Reverse Proxy issues, so please bear with me)

Seems like it’s your code located at /auth/twitch/callback that isn’t do what you expect it to do.

It doesn’t seem like it’s a Nginx issue or a cloudflare issue. But a “your code” issue.

Since these are brownser steps cloudflare would block the browser the user is using which is isn’t
And you can see the cloudflare is not blocking the request getting to nginx.
You can see that nginx is getting the request.
So whatever is processing the request is not doing what it’s supposed to do and is redirecting to / after failing to process the ?code

This is how it determines if the player should see the auth or index page. I’m thinking it has to do with Cloudflare because the site works fine when it is not set to proxied, and is set to DNS only on Cloudflare. Or, how the callback/code is affected when the site is proxied somehow.

//set route to start OAuth link, this is where you define scopes to request
app.get('/auth/twitch', passport.authenticate('twitch', { scope: 'user_read' }));

//set route for OAuth redirect
app.get('/auth/twitch/callback', passport.authenticate('twitch', { successRedirect: '/', failureRedirect: '/' }));

//detect authentication and serve game page
app.get('/', function (req, res) {

    //successfully authenticated
    if (req.session && req.session.passport && req.session.passport.user) {
        res.sendFile('index.html', { root: 'client/html' });
    }

    //request authentication
    else {
        res.sendFile('auth.html', { root: 'client/html' });
    };
});

This would suggest the problem lies with passport when it’s ran thru a proxy.

So passport or whatever session system is passed to passport doesn’t like being behind a proxy.

So the issue is your nodeJS code and it’s ability to set session cookies.

So passport is completing the login, but it cannot correctly set the session cookie to “stick” the login.

How to fix that, depends on what is handling sessions for you

I use express and express-session.

So what does your express session setup look like?

Right now it looks like:

const sessionAuthentication = session({
    secret: config.twitch.sessionSecret, 
    resave: false, 
    saveUninitialized: false
});

But when I look it up, I see that there’s a proxy option that I can set! I will try that and get back to you.

it might be as simple as

// for nginx/nrgok
app.set('trust proxy', 1) // trust first proxy

added before this line.

I tend to run something similar to this (click thru for full code snippet/session setup)

You can also debug/determine if it’s this by logging sessionID’s and see if the sessionID is constantly changing rather than “sticking” like it should.

Im taking a look at the documentation at
Express behind proxies (expressjs.com)

Would you know how I could debug the X-Forwarded-For header so I can see whats going on?

is the code in my example not working? (it’s what I use on live behing a nginx proxy)

This should point you in the right direction.
Depending on your NGINX and Cloudflare config, there might not be a X-Forwarded-For

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

No it wasn’t working for me. My console is showing Cloudflare’s IP in the header

'x-forwarded-for': '2601:203:400:fd40:bd49:acb0:9fb8:19dc, 172.69.142.83',

Thats expected since it was forwarded from cloudflare?!

if you are getting this to look up for a “trust proxy” hard coded value, DON’T since Cloudflare IP’s will change. Leaving your code not working.

So trust proxy with a boolean true is preferred. But I don’t proxy behind cloudflare. So there might be sone cloudflare specific instructions for node/express session

That might be a trust proxy of 1

Yea there must be since setting it to true doesn’t seem to work.

Under true

You want to also do

When setting to true, it is important to ensure that the last reverse proxy trusted is removing/overwriting all of the following HTTP headers: X-Forwarded-For, X-Forwarded-Host, and X-Forwarded-Proto otherwise it may be possible for the client to provide any value.

as the express notes say to remove those headers. (Which can be done in nginx)

or you’ll need to dig out for what works well when behind a double proxy and determine if the issue is being double proxied or a SSL Schnanigan

Since you might find the problem is

Browser → HTTPS To cloudlfare → cloudflare internal to https nginx → nginx proxy non ssl to node

Where

Browser → HTTPS To cloudlfare → cloudflare internal to non http nginx → nginx proxy non ssl to node

Which seems unlikely.

Also I explicity set these headers in my nginx config:

Copy/paste from production

    location / {
        proxy_pass OMMITTED

           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection 'upgrade';
           proxy_set_header Host $host;
           proxy_cache_bypass $http_upgrade;
           proxy_redirect off;
           proxy_http_version 1.1;
           proxy_set_header Host $host;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_set_header X-Forwarded-Proto $scheme;
    }

Not sure if that will cause a difference for you, since I’m not behind cloudflare.

So I can confirm that the left-most entry in the X-Forwarded-For header is the client IP, which means trust proxy = true should work, but it doesn’t seem to be. Could this narrow it down to an SSL issue?

I found that cloudflare sends its own header with the client IP and has a resource on restoring them: Restoring original visitor IPs – Cloudflare Help Center

Didn’t help, and I am not sure if im even supposed to be going this route.

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