#rate limit proxy, oauth backend limits, trusted IP

15 messages · Page 1 of 1 (latest)

rain sierra
#

Hi Lichess-Devs,

I'm building a scalable chess SaaS platform with a NestJS backend and an open-source Vue 3 frontend (https://github.com/ImMoSer/extrapawn.com). I am currently implementing a sync feature for user studies using the study:read and study:write OAuth scopes. (for using --header 'Authorization: Bearer YOUR_SECRET_TOKEN')
I want to design the architecture right from the start to avoid 429 errors and ensure security. I have three specific questions regarding rate limiting:

  1. Backend as Proxy (Preferred): If my backend securely stores the OAuth tokens and proxies the API requests to Lichess, are the rate limits evaluated per user-token or strictly against my server's IP? If it's IP-based, what is the recommended global rate limit (req/s) I should configure for my backend's request queue?
  2. Trusted IP: If the limits are heavily IP-based, is there a process to register a backend IP as a "trusted IP" for a legitimate OAuth application?
  3. Client-Side Requests (Alternative): If I am forced to run the requests directly from the client's browser to avoid bottlenecking my backend IP, what are the recommended cooldowns and concurrency limits specifically for study read/write operations?

Thanks in advance for the technical insights!

ripe chasm
#

rate limits use both userId and IP address. It's always better for scaling to run requests from the clients, but to some extent you can do it from a server as well

#

streamed requests are usually limited by concurrency rather than req/s

rain sierra
# ripe chasm for specifics, we'll need to know which endpoints exactly you want to use: https...

@thibault Thanks for the quick clarification!

I would actually love to run the requests directly from the client to scale infinitely, but proxying through my backend keeps the user's OAuth tokens safely encrypted in my DB (preventing frontend XSS risks).

Here are the specific endpoints I need for the sync feature:

Must-have:

  • POST /api/study/{studyId}/import-pgn (Import PGN into a study)
  • DELETE /api/study/{studyId}/{chapterId} (Delete a study chapter)

Nice-to-have:

  • POST /api/study (Create a new study)
  • GET /api/study/{studyId}.pgn (Export all chapters for private study workflows)

One architectural question: I couldn't find an endpoint to simply update the PGN/moves of an existing chapter. Is the recommended workaround to DELETE the old chapter and then POST (import) the new PGN, or am I missing a better approach?

Given these endpoints and the backend-proxy approach, what specific concurrency or req/s limits should I enforce on my server's job queue to ensure my IP doesn't get blocked?

ripe chasm
#

I would actually love to run the requests directly from the client to scale infinitely, but proxying through my backend keeps the user's OAuth tokens safely encrypted in my DB (preventing frontend XSS risks).

#

preventing XSS is not hard, and shouldn't stop you from doing what you love

#

also what do you mean by "OAuth tokens safely encrypted in my DB". It has to be 2-way encryption so you can send them to lichess, so not so safe

#

the other endpoints have generous limits that you should never hit

rain sierra
#

@thibault Thanks! The Scala snippet and your reality check on 2-way encryption were exactly what I needed to make the final architectural decision. Client-side requests it is.

Could I get a quick feedback on my other question regarding chapter updates?
I need to update the PGN/moves of an existing chapter. I noticed POST /api/study/{studyId}/{chapterId}/tags explicitly states: "Moves are just ignored."

Since there doesn't seem to be a direct PUT/PATCH endpoint for chapter moves, is the standard workaround to simply DELETE the old chapter and POST (import) a new one with the updated PGN, or am I missing a better approach?

ripe chasm
#

by updating moves, you mean replacing the entire move tree of a chapter?

rain sierra
# ripe chasm by updating moves, you mean replacing the entire move tree of a chapter?

yes. for example:
old_tree:1. d4 d5 2. e4 dxe4 3. Nc3 Nf6 4. f3 exf3 5. Nxf3 Bg4
new_tree:1. d4 d5 2. e4 dxe4 3. Nc3 Nf6 4. f3 exf3 (4... e3 5. Bxe3) 5. Nxf3 Bg4 6. h3 Bf5 (6... Bh5) (6... Bxf3)
or new_tree: 1. e4 e5 2. d4 exd4 3. Nf3 Nc6 4. Bc4 d6 5. O-O (can bee worse for parsing, therefore better to update whole move tree of a chapter) - api like "update chapter"

ripe chasm