Privacy Policy - Sesh Hub
Website: https://hub.seshsofa.nl
Last updated: 16 September 2026
1. Who we are
Sesh Hub ("we", "us" or "our") operates the website and web application available at https://hub.seshsofa.nl (the "Service").
We are based in the Netherlands. For the purposes of the General Data Protection Regulation (GDPR) and the Dutch Implementation Act (Uitvoeringswet AVG), we are the controller of the personal data described in this policy.
Contact. Privacy questions and data subject requests: GoatOps@stupid.systems
Postal address. Louwesweg 1, 1066EA Amsterdam, The Netherlands.
2. What this policy is
Sesh Hub is a small community site for the Sesh Sofa crew. You sign in with Discord or YouTube, and we keep an account record for you in a database on our server.
We want to be exact about that, because an earlier version of this policy claimed we stored nothing at all. That was wrong. We do store personal data: your Discord ID, your display name, your avatar URL, your YouTube channel if you link one, and a login session.
This policy lists every category of personal data we hold, why we hold it, when it is created, who can read it, when it changes, and when it is deleted.
3. How you sign in
Authentication is entirely via OAuth. We never see or store a password.
Discord. We request the scopes identify and guilds.members.read. identify returns your Discord user ID, username, global display name and avatar hash. guilds.members.read lets us read your role list in the Sesh Sofa Discord server, which is how we decide whether you are a member, a skater, a host or an admin. We do not request the email scope, so Discord does not give us your email address.
YouTube (Google). We request the scope youtube.readonly, with offline access so we receive a refresh token. This returns your channel ID, channel title and channel thumbnail, and lets us list the videos on your own channel.
Both flows use PKCE (S256) and a state parameter to prevent request forgery.
Your Discord role IDs are not stored. We read them at the moment you sign in, convert them into a single role label (admin, skater, member or pending) plus a host yes/no flag, and store only that result.
4. What we store, and its full lifecycle
Our database is a SQLite file on the server that runs the Service.
4.1 Your account (users table)
What: an internal account ID, your username, display name, avatar URL, role label, host flag, Discord ID, Discord username, YouTube channel ID, YouTube channel title, your YouTube OAuth refresh token, the time of your last YouTube sync, and creation and last-updated timestamps.
Why: to recognise you across visits, to show your name and avatar in the interface, to decide what you are allowed to see and edit, and to fetch your clips if you have linked YouTube.
Created: the first time you sign in with Discord or YouTube.
Read: on every request you make while signed in, to resolve your session to an account. Your display name is also shown publicly as the author of any article you write.
Updated: on every subsequent sign-in. We re-copy your current username, display name, avatar and roles from the provider, so changing your name or avatar on Discord changes it here the next time you log in. Linking or unlinking a provider also updates this record.
Deleted: by you at /account, or by an administrator. Articles you wrote stay published with the byline "Former member". See section 4.5.
The refresh token deserves a specific mention: it is a long-lived credential that lets us request read-only access to your YouTube channel without you signing in again. It is stored in the database in plain text. It is cleared when a YouTube account is unlinked or the account is deleted. You can also revoke it yourself at any time from your Google account's security settings, which invalidates it immediately regardless of what we hold.
4.2 Your login session (sessions table)
What: a SHA-256 hash of your session token, your account ID, an expiry time and a creation time.
The session token itself is a 256-bit random value. The plain value exists only in the cookie in your browser; we store only its hash, so the contents of our database cannot be used to impersonate you.
We do not store your IP address or User-Agent.
Why: to keep you signed in between requests.
Created: each time you sign in. Valid for 30 days.
Read: on every request, to look up your account.
Updated: never. Sessions are created and deleted, not modified.
Deleted: when you click log out, which deletes all of your sessions (every browser and device). Expired session rows are also purged when the server starts. All of your sessions are deleted if your account is deleted.
4.3 Your skater profile (skater_profiles table)
What: a public slug, your skater name, your real name, a biography, your stance, a roster status, avatar and banner URLs, your location, sponsors, social links, signature tricks, and a featured video ID.
Why: to show the team roster at /team and your own profile page at /team/{slug}.
Created: automatically, the first time you sign in holding the skater or admin role in the Sesh Sofa Discord. Your skater name is initially taken from your Discord username, and is kept in step with it on subsequent visits. The check that creates it runs on every request you make, so as long as your account exists and still holds the role, a profile will exist.
Read: this profile is public. Anyone on the internet, signed in or not, can see it. Note in particular that the name shown publicly is your real name if you have filled it in, and falls back to your skater name only if you have not. Your location and biography are also shown publicly when set. Please do not put anything in these fields that you would not want a stranger to read.
Updated: by you, at /dashboard/profile. That form currently edits your real name, biography, stance, location and featured video. An administrator can separately change your roster status.
Deleted: when your account is deleted, or by an administrator.
4.4 Your access request (access_requests table)
What: your account ID, a status of pending, approved or rejected, the account ID of the administrator who reviewed it, and timestamps.
Why: if you sign in but are not a member of the Sesh Sofa Discord server, you land in an approval queue rather than getting access.
Created: when you ask for access. Read: by administrators reviewing the queue, and by you to see your own status. Updated: when an administrator approves or rejects it; approval also changes your role to member. Deleted: together with your account.
4.5 Articles you write (articles table)
Articles record the account ID of their author, and your display name is published alongside the article. Article text is written by you and may contain whatever you put in it.
If your account is deleted, authorship is reassigned to a reserved "Former member" record so the article stays on /news. The byline no longer shows your name.
4.6 Cached clips from your YouTube channel (youtube_videos table)
What: for up to 50 recent uploads on a linked channel, the video ID, your channel ID, title, description, publication date, thumbnail URL, duration, view count, like count and tags.
Why: so the /videos gallery and skater profiles load from our database instead of calling the YouTube API on every page view.
Created and updated: in the background when a signed-in skater visits the Service and the cache for their channel is more than an hour old.
Read: publicly, on /videos and on skater profile pages.
Deleted: when your account is deleted, or when an administrator deletes the account that owned the channel.
4.7 Episode archive (episodes table)
The archive of past Spot Challenge episodes at /episodes includes a winner name for each episode. These are community handles and channel names, some of them seeded from the show's history, not account records. They are public.
4.8 Server logs
The application writes error-level logs to standard output. These can include an account ID when something fails for a specific user, for example a failed YouTube sync. The application does not keep an HTTP access log, and does not write request paths, IP addresses or User-Agent strings to its logs.
The Service sits behind a reverse proxy, which may keep its own request logs at the infrastructure level, including IP addresses, according to its default configuration.
There is also an unused sync_logs table in our database schema. Nothing ever writes to it; we mention it only for completeness.
4.9 What we do not do at all
We do not send email. There is no newsletter and no notification system. There is no file upload feature, so you cannot upload photos or documents to us. We do not sell, rent or trade personal data. We do not profile you, build advertising audiences, or use your data for anything beyond operating the site.
5. Cookies
| Cookie | Purpose | Lifetime | Notes |
|---|---|---|---|
seshhub_session |
Keeps you signed in | 30 days | Strictly necessary. HttpOnly, SameSite=Lax, and Secure in production. Contains a random token, no personal data. |
seshhub_oauth |
Holds the OAuth state and PKCE verifier during sign-in |
10 minutes | Strictly necessary. Deleted as soon as sign-in completes. |
seshhub_consent |
Remembers whether you allowed Google Analytics | 180 days | HttpOnly, SameSite=Lax, and Secure in production. Values yes or no. |
| Google Analytics cookies | Audience statistics | Set by Google, typically up to 2 years | Not strictly necessary. Only set after you click Allow. See section 6. |
Disabling the two strictly necessary cookies will stop you from being able to sign in. You can control all cookies through your browser settings. You can change the analytics choice by clearing seshhub_consent and answering the banner again.
6. Third parties, and who receives your IP address
Any time your browser loads something from another company's server, that company receives your IP address, because that is how the internet works. The following are loaded by pages on this Service:
- Google Analytics 4, from
googletagmanager.com, only after you allow it. Without that choice, the tag is not sent to your browser at all. - Web fonts from
fonts.cdnfonts.com, on every page. These faces are commercially licensed, so we load them from the CDN rather than copying the files onto our server. - YouTube video thumbnails from
img.youtube.comandi.ytimg.com, on the videos gallery, episode archive and profile pages. - YouTube video players from
youtube-nocookie.com, on skater profile pages that have clips. We deliberately use YouTube's privacy-enhanced domain, which does not set tracking cookies until you press play. - Discord avatar images from
cdn.discordapp.com, wherever an avatar is displayed. These are loaded withreferrerpolicy="no-referrer", so Discord is not told which page you were on.
Our server also talks to these services directly. In those cases your IP address is not sent; ours is.
- Discord's API, during sign-in, to read your profile and your roles in the Sesh Sofa server.
- Google's YouTube Data API, during sign-in and during clip sync, to read your channel and its public videos.
- Subotto (
subotto.seshsofa.nl), to fetch current episode information for the homepage. This is an anonymous request containing no information about you.
Each of these companies handles your data under its own privacy policy. You can revoke our access to your Discord or YouTube account at any time from that platform's own settings.
7. Purposes and legal basis
| What we do | Why | Legal basis |
|---|---|---|
| Create and maintain your account record | You cannot use a members' site without an account | Art. 6(1)(b) - performance of a contract, being the service you signed up for |
| Keep you signed in via a session cookie | Otherwise you would log in on every page | Art. 6(1)(b), and Art. 6(1)(f) legitimate interest in account security |
| Read your Discord roles to decide your permissions | To keep members' areas restricted to members | Art. 6(1)(f) - legitimate interest in access control |
| Publish your skater profile and article authorship | This is the purpose of the roster and the news section, and you control the content | Art. 6(1)(f), with your role in publishing it |
| Cache your YouTube clips | To show the gallery without hammering the YouTube API | Art. 6(1)(f) - legitimate interest in a functioning site |
| Google Analytics | Audience statistics | Art. 6(1)(a) - consent, via the banner. Declining (or ignoring the banner) means the tag never loads. |
8. Retention
- Account record: kept until you delete it at
/account, or an administrator deletes it. - Session record: valid for 30 days. Logging out deletes every session for your account. Expired rows are purged when the server starts.
- Skater profile: kept until the account is deleted, or an administrator removes the profile.
- Cached YouTube clips: kept until the owning account is deleted.
- Access requests: kept until the account is deleted.
- Articles and episode entries: kept as part of the site's published archive. Deleted authors are shown as "Former member".
9. Your rights under the GDPR
You have the right of access (Art. 15), rectification (Art. 16), erasure (Art. 17), restriction (Art. 18), data portability (Art. 20), and objection (Art. 21).
How to exercise these rights. Most of them are on /account while you are signed in: unlink a provider, download a JSON export of your account, profile and access request, or delete the account. Logging out ends every session. You can also email the contact address in section 1. We will respond within one month, as Art. 12(3) requires.
- Access or portability: use Download my data on
/account, or ask us by email. - Erasure: use Delete my account on
/account. That removes your account record, sessions, access request, skater profile and cached clips. Articles stay published as "Former member". - Rectification: most profile fields update themselves from Discord or YouTube on your next sign-in. Your biography and location are yours to edit at
/dashboard/profile. - Objection or restriction: tell us what you object to and we will stop it or explain why we believe we may continue.
Some of the underlying personal data also lives with Discord and Google, and we cannot reach into their systems. Revoking our OAuth access from their settings pages is immediate and does not require us.
You have the right to lodge a complaint with the Dutch Data Protection Authority, the Autoriteit Persoonsgegevens: https://autoriteitpersoonsgegevens.nl
10. Security
What is actually true about how we protect this data:
- Session tokens are stored as SHA-256 hashes, so a copy of our database does not let an attacker log in as you.
- Session tokens are 256 bits of cryptographic randomness.
- The session cookie is
HttpOnly, so scripts in the page cannot read it, andSameSite=Lax. - Traffic is served over HTTPS in production, and the session cookie is marked
Securethere. - Both OAuth flows use PKCE and a
stateparameter. - We never receive or store a password.
- We request the narrowest OAuth scopes the Service can work with, and specifically do not request your email address from Discord.
What we are not going to claim: that a breach is impossible. The previous version of this policy said our architecture "eliminated the possibility of a data breach". It does not. We hold a database with personal data in it, including YouTube refresh tokens in plain text, on a single server. We keep the amount of data small and the attack surface narrow, and that is a meaningful reduction in risk, but it is not immunity.
11. Age restriction - 18 years and over
The Service is intended for people aged 18 or over. If you are under 18, please do not use it.
We do not verify anyone's age, and we have no practical way to do so. If we become aware that an account belongs to someone under 18, we will delete it and its associated data. A parent or guardian who believes their child has used the Service should contact us at the address in section 1.
12. Where your data is processed
The Service runs on a single virtual private server in Amsterdam, the Netherlands. The database file sits on that server.
Some of the third parties in section 6 are based in the United States, including Google and Discord. When your browser loads their resources, or when our server calls their APIs, data reaches them there. Those transfers rely on the safeguards those companies provide, such as the EU-US Data Privacy Framework and standard contractual clauses. We have no separate transfer mechanism of our own to offer beyond choosing not to send them more than is necessary.
13. Changes to this Privacy Policy
We will update this policy when what we do changes, and change the "Last updated" date at the top. If we make a change that materially affects you, we will try to say so on the site rather than quietly editing this page.
14. Contact
Privacy questions and data subject requests go to the address in section 1.
This policy describes Sesh Hub as it is actually built. If you find something in here that does not match how the Service behaves, please tell us - that is a bug in the policy and we want to correct it.
