Skip to content
This repository was archived by the owner on Jul 28, 2026. It is now read-only.

Commit d0a9d76

Browse files
committed
fix: derive rpID/origin from request headers instead of static defaults
1 parent 7b1df8c commit d0a9d76

1 file changed

Lines changed: 22 additions & 9 deletions

File tree

routes/passkeys.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,18 @@ import { logActivity } from '../services/activity.js';
1414
const router = Router();
1515

1616
const RP_NAME = 'ZeroHost';
17-
const RP_ID = process.env.WEBAUTHN_RP_ID || 'localhost';
18-
const ORIGIN = process.env.WEBAUTHN_ORIGIN || 'http://localhost:3000';
17+
18+
function getWebAuthnConfig(req) {
19+
if (process.env.WEBAUTHN_ORIGIN && process.env.WEBAUTHN_RP_ID) {
20+
return { origin: process.env.WEBAUTHN_ORIGIN, rpID: process.env.WEBAUTHN_RP_ID };
21+
}
22+
const host = req.headers.host || 'localhost:3000';
23+
const proto = req.headers['x-forwarded-proto'] || (req.socket?.encrypted ? 'https' : 'http');
24+
return {
25+
origin: `${proto}://${host}`,
26+
rpID: host.split(':')[0],
27+
};
28+
}
1929

2030
const challengeMap = new Map();
2131

@@ -28,7 +38,7 @@ function getClientIp(req) {
2838
router.post('/passkeys/register/begin', authenticateToken, async (req, res) => {
2939
try {
3040
const userId = req.user.userId;
31-
const userEmail = req.user.email;
41+
const { rpID, origin } = getWebAuthnConfig(req);
3242
const user = await query(
3343
'SELECT id, email, username FROM users WHERE id = ?',
3444
[userId]
@@ -50,7 +60,7 @@ router.post('/passkeys/register/begin', authenticateToken, async (req, res) => {
5060

5161
const options = await generateRegistrationOptions({
5262
rpName: RP_NAME,
53-
rpID: RP_ID,
63+
rpID,
5464
userName: user[0].email,
5565
userDisplayName: user[0].username,
5666
attestationType: 'none',
@@ -86,11 +96,12 @@ router.post('/passkeys/register/complete', authenticateToken, async (req, res) =
8696

8797
challengeMap.delete(userId);
8898

99+
const { rpID, origin } = getWebAuthnConfig(req);
89100
const verification = await verifyRegistrationResponse({
90101
response,
91102
expectedChallenge: expectedChallenge.challenge,
92-
expectedOrigin: ORIGIN,
93-
expectedRPID: RP_ID,
103+
expectedOrigin: origin,
104+
expectedRPID: rpID,
94105
});
95106

96107
if (!verification.verified || !verification.registrationInfo) {
@@ -152,8 +163,9 @@ router.post('/passkeys/login/begin', async (req, res) => {
152163
transports: k.transports ? k.transports.split(',') : ['internal'],
153164
}));
154165

166+
const { rpID } = getWebAuthnConfig(req);
155167
const options = await generateAuthenticationOptions({
156-
rpID: RP_ID,
168+
rpID,
157169
allowCredentials,
158170
userVerification: 'preferred',
159171
});
@@ -200,11 +212,12 @@ router.post('/passkeys/login/complete', async (req, res) => {
200212
return res.status(400).json({ error: 'Passkey not found' });
201213
}
202214

215+
const { rpID, origin } = getWebAuthnConfig(req);
203216
const verification = await verifyAuthenticationResponse({
204217
response,
205218
expectedChallenge: expectedChallenge.challenge,
206-
expectedOrigin: ORIGIN,
207-
expectedRPID: RP_ID,
219+
expectedOrigin: origin,
220+
expectedRPID: rpID,
208221
credential: {
209222
id: isoBase64URL.toBuffer(passkey.credential_id),
210223
publicKey: isoBase64URL.toBuffer(passkey.public_key),

0 commit comments

Comments
 (0)