Parental controls and PIN-locked categories on Xbox
The gates are set in the browser and enforced on the console. When the console cannot reach the server to check, they close rather than open.
Parental controls follow the same split as everything else on the console: configured in the web console or the Windows app, enforced on the Xbox. The console is where a gate stops someone, not where it is defined.
That is the right way round. A PIN set from a sofa is a PIN typed in front of whoever is on the sofa.
Four controls, and they are not the same control
They get conflated, and they behave differently.
The account PIN protects profile switching. It stops a child selecting the adult profile from the picker.
Kid mode is a profile kind. A kid profile gets a restricted experience plus two time-based gates, covered below.
Maximum rating is a per-profile cap, and there are 2 of them rather than 1. Films and television are capped separately, because the rating systems are separate and a household fine with a 12 rated film may not be fine with the television equivalent.
Adult category handling has a genuine fork in behaviour. It is the one most worth understanding.
Hiding is not the same as locking
A profile either hides adult content or gates it. Different code paths, different experiences.
If the profile hides it, the channels are filtered out before the list is built. There is no gate prompt, because there is nothing to prompt about. A viewer on that profile does not learn that anything was removed.
If the profile gates it, the channels are visible and opening one asks for the PIN. I got this wrong on first read: the gate has four conditions, not three, and every one of them must hold at once. Hiding is off, the profile actually has a PIN set, no session unlock is already active, and the profile is flagged to require the PIN for adult content. A profile with no PIN configured cannot gate anything, which is the usual cause of "I turned it on and nothing happened".
Once a PIN is accepted, the unlock is held for the session against that profile's id. You are not re-prompted per channel. Switching profile or restarting the app drops it, and a profile with an empty id can never inherit somebody else's unlock.
Kid profiles: two gates, evaluated separately
A kid profile can be locked for either of 2 reasons, and they are independent.
The daily limit is stored in minutes and evaluated in seconds. Usage is kept per local date, so the count resets when the stored date stops matching today rather than on a timer. An absent or zero allowance disables the check rather than locking immediately.
The bedtime window is stored as start and end minutes and evaluated against local time, which lets it wrap past midnight without special-casing.
Each has its own override, so unlocking bedtime for a Friday film does not also hand over the rest of the week's daily allowance. The daily limit is checked first, so a profile over its allowance reports that rather than the time of day.
Profile kind=kid, dailyTimeLimitMinutes=90, bedtime 20:30 to 07:00
Watched today 4,900 seconds
Evaluation 4,900 >= 90 x 60 -> daily limit reached, locked
What happens when the console cannot reach the server
This is the part that separates a real gate from a decorative one.
The gates fail closed. If the profile fetch fails, the console does not shrug and let everything through; it falls back to a persisted last-known-good snapshot and keeps enforcing. There is a test per gate covering that path, because it is exactly the behaviour that decays silently if nobody is checking.
The same principle explains something about startup that looks like an oversight. The profile picker never auto-advances to whoever watched last, even though skipping it would measurably shorten the time from launch to Home, and the old cold-start target of under 3 seconds assumed exactly that shortcut. It was rejected permanently. Choosing a profile is a security boundary, and a boundary you cross automatically is not one.
PINs are not stored as PINs
A PIN never sits on disk as a PIN. It is hashed with PBKDF2-SHA256 at 100,000 iterations, with a 16 byte random salt and a 32 byte derived key, in the same format the account services use. The stored value carries its own scheme version and iteration count, so the cost can be raised later without invalidating existing PINs. Verification is constant time: a wrong PIN takes the same time to reject however much of it was right.
A 4 digit PIN is still a 4 digit PIN. The hashing means someone with the device's storage does not get your PIN for free, which is a different threat from someone guessing it at the sofa.
Setting it up
Everything above is configured in the web console under Profiles, or in the Windows app. The Xbox reads the result. The Profiles destination in the console's app navigation is a placeholder, so there is no route to change any of this from the sofa. That is the point, not a limitation.
If a gate is not behaving as you expect, the usual cause is a PIN never having been set on the profile you are testing. Installing on Xbox covers pairing, and navigating with the controller covers what the picker's buttons do.
What this article measured21 claims, each with the evidence behind it
| Claim | Evidence | Counted |
|---|---|---|
| A parental PIN is never stored as a PIN. It is hashed with PBKDF2-SHA256 at 100,000 iterations with a 16 byte random salt and a 32 byte derived key, and verified in constant time. | n = 1 | Aug 31, 2026 |
| Adult content has two distinct behaviours, not one. A profile can hide it entirely, in which case there is nothing to unlock, or show it behind a PIN gate. A profile set to hide never sees a gate prompt. | n = 1 | Aug 31, 2026 |
| Once a PIN is entered, the unlock is held for the session against that profile id, so a viewer is not re-prompted for every channel. | n = 1 | Aug 31, 2026 |
| A kid profile can be locked for two separate reasons, each overridable on its own: a daily watch limit measured in seconds against the profile's minute allowance, and a bedtime window. | n = 1 | Aug 31, 2026 |
| When the profile fetch fails, the kid gates close rather than open, backed by a persisted last-known-good snapshot, and there is a test per gate. | n = 1 | Aug 31, 2026 |
| The profile picker never auto-advances to the last profile used, even though skipping it would measurably shorten startup. Automatic selection was rejected permanently because profile choice is a security boundary. | n = 1 | Aug 31, 2026 |
| The stored hash carries its own scheme version and its iteration count, so the cost can be raised later without invalidating existing PINs. | n = 1 | Sep 1, 2026 |
| Verification rejects a stored value that is not exactly four parts, does not begin with the scheme marker, has a non-positive iteration count, or fails to decode, rather than throwing. | n = 4 | Sep 1, 2026 |
| Parental locks are one of the thirteen synced state families, so a lock set in a browser reaches the console rather than living on one device. | n = 1 | Sep 1, 2026 |
| Kid time limits are evaluated against device-local usage rather than a household total, so the allowance is per device rather than pooled. | n = 1 | Sep 1, 2026 |
| The daily counter resets by comparing the stored local date against today rather than on a timer, so a device that was off overnight starts the new day correctly. | n = 1 | Sep 1, 2026 |
| The lock computation returns immediately for a profile that is not a kid profile, so the time rules cannot accidentally apply to an adult profile. | n = 1 | Sep 1, 2026 |
| The two kid gates are evaluated in a fixed order, daily limit before bedtime, so a profile over its allowance reports that rather than reporting the time of day. | n = 1 | Sep 1, 2026 |
| A daily allowance that is absent or not positive disables the check rather than locking immediately, so an unset limit is not a zero limit. | n = 1 | Sep 1, 2026 |
| Bedtime is stored as start and end minutes rather than clock times, which is what lets a window wrap past midnight without special cases. | n = 1 | Sep 1, 2026 |
| The adult PIN gate engages only when four things hold at once: hiding is off, the profile has a PIN, no session unlock is active, and the profile requires a PIN for adult content. | n = 4 | Sep 1, 2026 |
| The session unlock is keyed by profile identifier and explicitly skips an empty one, so an unidentified profile cannot inherit somebody else's unlock. | n = 1 | Sep 1, 2026 |
| When a profile hides adult content the channels are excluded from the list rather than shown behind a gate, so a viewer on that profile is never told something was removed. | n = 1 | Sep 1, 2026 |
| The console's profiles destination on the 10-foot shell renders a placeholder, so there is no route to change any of these settings from the sofa. | n = 1 | Sep 1, 2026 |
| The empty profiles state tells the user to create one in the web console, naming the split rather than offering an on-console flow. | n = 1 | Sep 1, 2026 |
| A profile carries separate maximum ratings for films and for television rather than one combined cap. | n = 1 | Aug 31, 2026 |