Level 2 · Chapter 2
Access tokens
The identity payload every process and thread carries — the OS's answer to 'who is asking?'
Security framed every access decision as a comparison between a token and a security descriptor. This chapter is about the first half: the token — what's actually in it, and why "who is asking" turns out to be a much richer question than just a username.
What's actually inside a token
A token is far more than an account identifier. Concretely, it carries:
- A user SID — the security identifier for the signed-in identity.
- Group SIDs — every group the user belongs to, each individually usable in an access check, and each individually able to be enabled, disabled, or marked deny-only — a detail that matters more than it sounds like it should (more on that below).
- Privileges — special, global capabilities like
SeDebugPrivilegeorSeBackupPrivilege, covered in full in Privileges (Se*). - An integrity level — a Mandatory Integrity Control label, covered in UAC, integrity levels, and the secure desktop.
- For AppContainer processes, an AppContainer SID and capability SIDs — see AppContainers & capabilities.
Every one of these fields participates in access checks. Two tokens with the same user SID can behave completely differently if their group memberships, privileges, or integrity levels differ.
Primary tokens vs. impersonation tokens
Every process has exactly one primary token, assigned at creation and describing the identity the process runs as by default. A thread, though, can temporarily adopt a different impersonation token — exactly the mechanism named pipes uses to let a privileged service act, briefly, as if it were the connecting client. While impersonating, access checks performed by that thread are evaluated against the impersonation token, not the process's primary one; when impersonation ends, the thread reverts to acting as the process's own identity.
This split is what lets a single long-running privileged service correctly enforce per-caller access decisions instead of either trusting every caller equally or requiring a brand-new process per caller.
Why group membership alone doesn't decide anything
Group SIDs in a token aren't a flat "is a member of" list evaluated independently — each one carries attributes that change how it counts:
- Enabled groups participate normally in access checks that look for an allow.
- Deny-only groups exist specifically to let a token be used in deny checks without granting the corresponding allow — a mechanism that shows up in filtered tokens, where the Administrators SID is often present as deny-only, so an explicit deny-ACE for Administrators still applies even though the token's ordinary elevated rights have been stripped.
- Disabled groups are present in the token's structure but don't count toward either allow or deny checks at all.
This is a direct, concrete answer to "why doesn't being in this group do what I expected" — the group being listed in a token isn't sufficient; its attribute matters just as much as its presence.
A worked example: a service accessing a resource on a user's behalf
A service that needs to act on a specific user's behalf — reading a file the user owns, say — has a choice: use its own (likely more privileged) identity, or impersonate the requesting user's token and let the ordinary access-check machinery decide whether that user is allowed to read the file. The second option is almost always the more correct design: it means the service never accidentally grants access the user themselves wouldn't have had, because the decision is delegated to the same Security Reference Monitor logic that would apply if the user tried directly.
A common mistake
Reducing a token to "the username" misses almost everything that actually determines behavior. A user can be a domain administrator and still be denied a specific operation because a privilege wasn't enabled on the current thread, or because their admin group SID is present only as deny-only in a filtered token. "What account is this" is a necessary question; it is very rarely a sufficient one.
Where this connects
- LSASS, SAM, and local security policy is where a token's initial contents get decided, at logon.
- Access checks & the Security Reference Monitor is the algorithm that actually consumes every field described here.