openvibers/openvibe.network Commits

Sign-in redirects get their own rate limit: /oauth/authorize (every site's sign-in and silent check, no password) shared the password endpoints' 5 a minute and refused 304 sign-ins from 15 visitors today; now 60 a minute, sign-in and registration keep 5 (#290)

OP OpenVibers committed 24 days ago · 8c14660988 · 3 files, +36 −3

Changes

ddiff --git a/deploy/nginx/openvibe.network.conf b/deploy/nginx/openvibe.network.conf
iindex 49182486..ee59b4cd 100644
---- a/deploy/nginx/openvibe.network.conf
++++ b/deploy/nginx/openvibe.network.conf
@@@ -15,6 +15,11 @@ limit_req_zone $binary_remote_addr zone=openvibenetwork_auth:10m rate=5r/m;
# Token issuance for apps (client credentials, code exchange, refresh): not a password check, so not the
# sign-in limit — a developer's app needs a few tokens a minute (one per audience) and got 503s at 5/min.
limit_req_zone $binary_remote_addr zone=openvibenetwork_token:10m rate=60r/m;
++# /oauth/authorize answers every site's sign-in, and every silent "already signed in?" check as a visitor opens another
++# OpenVibe site (about 10,000 a day): it checks no password, it redirects with the session the browser has. It shared
++# the password endpoints' 5 a minute, which refused 304 sign-ins from 15 visitors on 2026-10-20 (the owner among them,
++# signing in to openvibe.host); it has its own, generous zone.
++limit_req_zone $binary_remote_addr zone=openvibenetwork_authorize:10m rate=60r/m;
# ── HTTP → HTTPS redirect ──────────────────────────────────
server {
@@@ -73,8 +78,21 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
}
-- # ── Auth endpoints (strict rate limit) ──────────────────
-- location ~ ^/(api/auth/(register|login|anon-session)|oauth/authorize) {
++ # ── Sign-in redirects (their own limit, above) ──────────
++ location = /oauth/authorize {
++ limit_req zone=openvibenetwork_authorize burst=60 nodelay;
++ limit_req_status 429;
++ proxy_pass http://127.0.0.1:4000;
++ proxy_http_version 1.1;
++ proxy_set_header Host $host;
++ proxy_set_header X-Real-IP $remote_addr;
++ proxy_set_header X-Forwarded-For $remote_addr;
++ proxy_set_header CF-Connecting-IP $remote_addr;
++ proxy_set_header X-Forwarded-Proto $scheme;
++ }
++
++ # ── Password and account endpoints (strict rate limit) ──
++ location ~ ^/api/auth/(register|login|anon-session) {
limit_req zone=openvibenetwork_auth burst=5 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:4000;
ddiff --git a/server/deploy/nginx-generator.js b/server/deploy/nginx-generator.js
iindex 2df1e61f..f3854dbc 100644
---- a/server/deploy/nginx-generator.js
++++ b/server/deploy/nginx-generator.js
@@@ -23,10 +23,17 @@ const DEFAULT_SERVICE_MAP = {
rateZones: [
{ name: 'openvibenetwork_api', rate: '10r/s' },
{ name: 'openvibenetwork_auth', rate: '5r/m' },
++ { name: 'openvibenetwork_authorize', rate: '60r/m' },
],
locations: [
{
-- match: '~ ^/(api/auth/(register|login|anon-session)|oauth/(token|authorize))',
++ // Every site's sign-in and silent check: no password here, so not the password endpoints' 5 a minute.
++ match: '= /oauth/authorize',
++ rateZone: 'openvibenetwork_authorize',
++ rateBurst: 60,
++ },
++ {
++ match: '~ ^/(api/auth/(register|login|anon-session)|oauth/token)',
rateZone: 'openvibenetwork_auth',
rateBurst: 5,
},
ddiff --git a/test/api-rate-limit.test.js b/test/api-rate-limit.test.js
iindex ec8c3814..e7908f87 100644
---- a/test/api-rate-limit.test.js
++++ b/test/api-rate-limit.test.js
@@@ -13,4 +13,12 @@ assert.ok(src.includes("app.use('/api/auth/', rateLimit({ windowMs: 15 * 60_000,
assert.ok(src.includes("app.use('/api/v1/node-pairing', rateLimit({ windowMs: 60_000, max: 10 })"), 'pairing stays at 10 a minute');
const conf = fs.readFileSync(path.join(__dirname, '../deploy/nginx/openvibe.network.conf'), 'utf8');
assert.ok(/zone=openvibenetwork_api:10m rate=10r\/s/.test(conf), "nginx's /api/ zone is the 10 r/s the app now matches");
++// /oauth/authorize (every site's sign-in and silent check, no password) has its own zone: under the password
++// endpoints' 5 a minute it refused 304 sign-ins from 15 visitors on 2026-10-20. Sign-in and registration keep 5.
++assert.ok(/zone=openvibenetwork_authorize:10m rate=60r\/m;/.test(conf), 'authorize: 60 a minute per address');
++const block = (re) => { const m = re.exec(conf); assert.ok(m, String(re)); return conf.slice(m.index, conf.indexOf('}', m.index)); };
++assert.match(block(/location = \/oauth\/authorize \{/), /limit_req zone=openvibenetwork_authorize burst=60 nodelay;/);
++const strict = /location ~ (\S+) \{\s*limit_req zone=openvibenetwork_auth burst=5 nodelay;/.exec(conf);
++assert.ok(strict && /register\|login/.test(strict[1]) && !/authorize/.test(strict[1]), 'the strict zone covers sign-in and registration, not authorize');
++assert.ok(/zone=openvibenetwork_auth:10m rate=5r\/m;/.test(conf));
console.log('api rate limit: all checks passed');