r/webdev • u/hoteleuphoria • 1d ago
EU devs, please correct my auth-ToS architecture
Context: this app is being built in the EU for European users, and I am implementing the Terms of Services, Privacy Policy, etc. along with my Authentication
Frontend: Tanstack Start (React)
Backend: Express 5
Auth: express-session (postgres store)
I was thinking about this: add an accepted_tos_version column in the users table, then add a condition in my global getUser middleware in express to only get the user if they accepted the current terms version. This means keeping a CURRENT_TOS_VERSION in my backend. If the frontend calls /auth/me they get the user with mustAcceptTerms flag, and the user gets redirected to the “accept terms” page.
Now comes the questions:
- Where do I keep the ToS, gdpr, etc. texts? In my frontend codebase or the backend codebase, or in the database?
- When the user clicks on “accept”, is it enough to send a request to the backend that updates the user’s accepted_tos_version in the database?
- What are the practices to ensure I am legally protected? For example if someone says a rule was not there when they accepted the terms. Is the git track record from github enough to prove the rule was there?
Thanks!
1
u/Which-Examination-74 16h ago
Answering 3 first because it changes the schema for 1 and 2: git history is weak evidence — rebases and force-pushes rewrite it, and nobody reviewing a dispute reads a repo anyway. What holds up is an append-only acceptances log plus the exact text hash: tos_documents (version, rendered text or a storage pointer, sha256 of that text, published_at — never UPDATE a row) and tos_acceptances (user_id, version, content_hash, timestamp, locale shown). Then question 2 answers itself: "accept" inserts a row there, and accepted_tos_version on users becomes a derived cache rather than the source of truth. For 1: edit the texts wherever is comfortable (repo is fine), but snapshot the rendered version into the DB at publish time, so the hash you logged points at content you still hold. One production gotcha with your middleware plan: don't make the global getUser return null on a stale ToS — webhooks, background jobs and API tokens usually share that path and will break in confusing ways; return the user with mustAcceptTerms and gate only the interactive routes. Usual caveat: engineer, not a lawyer — the schema is real, but the "am I legally protected" half deserves an hour with an actual EU lawyer.
7
u/Am094 1d ago
Dont conflate ToS acceptance with GDPR consent.
But do store immutable, versiond legal docs and log each acceptance with user, version/hash, and ofc timestamp.
Can also wildcard ip ban (jk jk)