Problem:
Firebase Reverse Proxy Configuration Issue
Details:
I’m attempting to configure nginx as a reverse proxy for Firebase authentication endpoints, following Option 3 in the Firebase documentation.
Document:
Firebase Documentation: Best Practices for Handling Redirects
Error Message:
When making a GET request from the client’s JavaScript library to the Firebase authentication endpoint (https://example.ngrok-free.app/__/auth/handler), a 404 error occurs. It seems that the reverse proxy setup is not working as expected.
Outcome:
The GET request to https://example.ngrok-free.app/__/auth/handler?parameters results in a 404 Not Found error.
Expected Outcome:
I expect nginx to correctly proxy requests to https://example.firebaseapp.com/__/auth/handler when accessed through https://example.ngrok-free.app/__/auth/handler.
Additional Information:
I’m using ngrok to expose my local environment (http://localhost:3000) to a publicly accessible HTTPS domain (https://example.ngrok-free.app).
Below are my Docker and nginx configurations:
├── Dockerfile
├── dist
│ ├── client
│ │ ├── client.js
│ │ └── public
│ │ ├── bundle.js
│ │ └── index.html
│ ├── server
│ │ ├── app.js
│ │ └── generate-jwt.js
│ └── shared
│ └── firebaseConfig.js
├── docker-compose.yml
├── nginx.conf
├── package-lock.json
├── package.json
├── src
│ ├── client
│ │ ├── client.ts
│ │ └── public
│ │ └── index.html
│ ├── server
│ │ ├── app.ts
│ │ └── generate-jwt.ts
│ └── shared
│ └── key
│ └── AuthKey_example.p8
├── tsconfig.json
└── webpack.config.js
Dockerfile
FROM node:22.2.0
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install && npm cache clean --force
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/server/app.js"]
docker-compose.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
volumes:
- ./src:/usr/src/app/src
networks:
- frontend
nginx:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./src/client/public:/usr/share/nginx/html
networks:
- frontend
networks:
frontend:
driver: bridge
nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
server {
listen 80;
location / {
proxy_pass http://app:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 90s;
proxy_connect_timeout 90s;
proxy_send_timeout 90s;
}
location /__/auth {
proxy_pass https://example.firebaseapp.com;
}
}
}
Client.ts
import { initializeApp } from "firebase/app";
import { getAuth, signInWithRedirect, OAuthProvider } from "firebase/auth";
const firebaseConfig = {
apiKey: "MY_API_KEY_HERE",
authDomain: "MY_AUTH_DOMAIN_HERE",
projectId: "MY_PROJECT_ID_HERE",
storageBucket: "MY_STORAGE_BUCKET_HERE",
messagingSenderId: "MY_MESSAGING_SENDER_ID_HERE",
appId: "MY_APP_ID"
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
document.getElementById('apple-signin-button')!.addEventListener('click', () => {
const provider = new OAuthProvider('apple.com');
signInWithRedirect(auth, provider);
});
app.ts
import express from 'express';
import path from 'path';
const app = express();
app.use(express.static(path.join(__dirname, '..', 'client', 'public')));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '..', 'client', 'public', 'index.html'));
});
app.listen(3000, () => {
console.log('App listening on port 3000!');
});