WEB / WEB-12.01
Adding state to HTTP with cookies
Follow a language preference from Set-Cookie to the Browser jar and the next Cookie header to locate state transmission.
1. Core · Mechanism
Read every scenario without motion
Preference cookie included
- The first request has no preference
The jar starts empty. The browser prepares a request to library.outreason.example/books. Language or view preferences are not authentication results.
- Browser · cookie jar
- Jar: empty
- Application · HTTP handler
- No request yet
- Request · context
- HTTPS · /books · same-site
- The first HTTP request arrived
This request has no preference Cookie field. The application can use its default language and view. An absent cookie is not a transport failure.
- Browser · cookie jar
- Waiting for response
- Application · HTTP handler
- No Cookie → en / comfortable
- Request · context
- First GET received
- The response prepares cookie fields
The application prepares two separate Set-Cookie response fields: hd_language=tr; Path=/ and hd_view=compact; Path=/. These preference values are not a session identity.
- Browser · cookie jar
- Jar still empty
- Application · HTTP handler
- Two Set-Cookie fields ready
- Request · context
- Waiting for response
- The cookie response reached the browser
The browser received headers for its own cookie processing. Set-Cookie is not an ordinary header exposed through frontend fetch response headers.
- Browser · cookie jar
- Headers arrived; storage separate
- Application · HTTP handler
- Set-Cookie response sent
- Request · context
- Response headers received
- The jar is local browser state
In this controlled example the browser accepts both cookies; host-only scope and Path=/ metadata belong to the jar. Acceptance is not a general browser guarantee.
- Browser · cookie jar
- Jar: hd_language / hd_view
- Application · HTTP handler
- No later request yet
- Request · context
- Host-only · Path=/
- The later request selects candidates
The candidates are eligible in this fixture’s same host/path context. The request Cookie field contains only name=value pairs; Path is not copied into it.
- Browser · cookie jar
- Cookie: hd_language=tr; hd_view=compact
- Application · HTTP handler
- Request not received
- Request · context
- Preparing GET /books
- The later request is in the application
The Cookie request field carries names and values. Response attributes are not carried there; the application validates supported preference values and otherwise selects defaults.
- Browser · cookie jar
- Waiting for response
- Application · HTTP handler
- Preference: tr / compact
- Request · context
- GET + Cookie name=value
- A preference is not a principal
The application selects presentation. Cookie inclusion proves neither verified identity nor resource permission; session and authorization models show those later decisions separately.
- Browser · cookie jar
- UI preference can be prepared
- Application · HTTP handler
- tr / compact; no authn established
- Request · context
- This request observation is complete
No preferences
- The first request has no preference
The jar starts empty. The browser prepares a request to library.outreason.example/books. Language or view preferences are not authentication results.
- Browser · cookie jar
- Jar: empty
- Application · HTTP handler
- No request yet
- Request · context
- HTTPS · /books · same-site
- The first HTTP request arrived
This request has no preference Cookie field. The application can use its default language and view. An absent cookie is not a transport failure.
- Browser · cookie jar
- Waiting for response
- Application · HTTP handler
- No Cookie → en / comfortable
- Request · context
- First GET received
- The response prepares cookie fields
The application prepares two separate Set-Cookie response fields: hd_language=tr; Path=/ and hd_view=compact; Path=/. These preference values are not a session identity.
- Browser · cookie jar
- Jar still empty
- Application · HTTP handler
- Two Set-Cookie fields ready
- Request · context
- Waiting for response
- The cookie response reached the browser
The browser received headers for its own cookie processing. Set-Cookie is not an ordinary header exposed through frontend fetch response headers.
- Browser · cookie jar
- Headers arrived; storage separate
- Application · HTTP handler
- Set-Cookie response sent
- Request · context
- Response headers received
- The jar is local browser state
In this controlled example the browser accepts both cookies; host-only scope and Path=/ metadata belong to the jar. Acceptance is not a general browser guarantee.
- Browser · cookie jar
- Jar: hd_language / hd_view
- Application · HTTP handler
- No later request yet
- Request · context
- Host-only · Path=/
- The later request selects candidates
In this alternative fixture the later request has no preferences: the user may have cleared them or browser state may not be carried. The application observes absence on this request without inventing the cause.
- Browser · cookie jar
- Later request: no Cookie
- Application · HTTP handler
- Request not received
- Request · context
- Preparing GET /books
- The later request is in the application
The Cookie request field carries names and values. Response attributes are not carried there; the application validates supported preference values and otherwise selects defaults.
- Browser · cookie jar
- Waiting for response
- Application · HTTP handler
- Default: en / comfortable
- Request · context
- GET + no preference Cookie
- A preference is not a principal
The application selects presentation. Cookie inclusion proves neither verified identity nor resource permission; session and authorization models show those later decisions separately.
- Browser · cookie jar
- UI preference can be prepared
- Application · HTTP handler
- en / comfortable; no authn established
- Request · context
- This request observation is complete
ACTORS · STATE · DATA FLOW
How does the next request remember the page language?
Duru selects Turkish and a compact view in the Atlas library. The next page should retain those choices. HTTP being stateless does not prohibit application memory: the meaning of a request does not depend on the connection that carried an earlier message. Continuity is built from information on later requests and application state.
A cookie is a small Browser-managed name/value record that can support this continuity. hd_language=tr and hd_view=compact are display preferences in our example. No login occurs, and neither value proves a user identity. This separates remembering state from establishing authentication.
Set-Cookie brings the server’s instruction to the Browser
The Application processes Duru’s selection and adds two separate Set-Cookie fields to its response. One contains hd_language=tr; Path=/ and the other hd_view=compact; Path=/. Each describes a separate cookie. Folding the two Set-Cookie fields into one comma-separated list is not a valid general combining method.
While the response travels, the Application has prepared the preference result but the Browser jar has not changed. On arrival, Browser policy determines acceptance, storage or rejection. Sending Set-Cookie and observing a stored cookie are separate steps. WEB-12.02 develops scope and lifetime; this example chooses one host, Path=/ and a Browser policy that allows storage.
Cookie expresses the Browser’s selection for a later request
When Duru opens the book list, the Browser selects eligible records and sends Cookie: hd_language=tr; hd_view=compact. The semicolon separates two name/value pairs. Attributes such as Path=/ from Set-Cookie are not repeated in the request Cookie field.
This does not send the response back. The Browser serializes eligible state from its jar for this request context. A cookie belonging to another site is not automatically included because it exists in the jar. Selection depends on host, path, lifetime and policy; reusing an HTTP connection does not replace that selection.
The server interprets the incoming data again
The Application parses both preferences on the second request. Our model allows tr/en for language and compact/comfortable for view. Valid pairs affect response presentation. Without them, the Application uses its en/comfortable defaults. Both results are explained by the endpoint contract.
A cookie value is client-supplied data. Its earlier issuance by the server does not make every later value inherently trustworthy. We accept a constrained preference here; roles, tenants and book ownership are not established from arbitrary cookie text.
Separate the cookie mechanism from the kind of state it carries
A cookie can hold a preference directly or carry an opaque handle to a server record. In the second design, the large state is not inside the Cookie header; the handle tells the Application which record to evaluate. WEB-13.01 develops that separation for sessions.
Set-Cookie is not the only creation mechanism: eligible cookies can also be created through script APIs. Restrictions such as HttpOnly define separate boundaries. Reading Set-Cookie through frontend response.headers is not a way to observe cookie acceptance; the Browser filters this response header from frontend access.
When does this state disappear?
If Duru clears the cookies, the next request may omit the preference pairs and receive the default view. This does not erase Atlas’s database or all server state. Dropping a Browser preference and changing application records are independent operations.
Explain the next request using three parts: the jar’s candidate records, the transmitted pairs and the limited result derived by the Application. A Turkish page alone does not identify which of these stages occurred.
2. Red · Trust & Impact
Read every scenario without motion
Preference present
- The preference request is ready
The browser preference in this example concerns language and layout. A request that has not reached the handler cannot establish an application decision.
- Browser
- hd_language=tr; hd_view=compact
- Preference handler
- Request not received
- Application decision
- No identity decision
- The preference input arrived
The ordinary preference request reached the handler. Presence or absence of cookie pairs describes this input, rather than an authenticated identity.
- Browser
- Awaiting result
- Preference handler
- Cookie pairs received
- Application decision
- No identity decision
- The allowed values were selected
The application uses languages=[tr,en] and views=[compact,comfortable]. This branch selects tr and compact from these sets.
- Browser
- Awaiting result
- Preference handler
- language=tr; view=compact
- Application decision
- No identity decision
- Preferences do not establish authority
Although language and layout are selected, the artifact establishes no login, role or tenant grant. A preference result cannot substitute for those decisions.
- Browser
- Awaiting result
- Preference handler
- Preference selection complete
- Application decision
- Presentation context only
- The presentation response is ready
The handler prepares the result for language tr and layout compact. This response is neither an authentication document nor approval of a sensitive action.
- Browser
- Awaiting result
- Preference handler
- Preference result prepared
- Application decision
- Presentation context only
- The preference result reached the browser
The browser received the selected presentation result. Cookie presence explains the preference source; it does not become identity evidence.
- Browser
- language=tr; view=compact
- Preference handler
- Response prepared
- Application decision
- No identity decision
Preference absent
- The preference request is ready
The browser preference in this example concerns language and layout. A request that has not reached the handler cannot establish an application decision.
- Browser
- No Cookie
- Preference handler
- Request not received
- Application decision
- No identity decision
- The preference input arrived
The ordinary preference request reached the handler. Presence or absence of cookie pairs describes this input, rather than an authenticated identity.
- Browser
- Awaiting result
- Preference handler
- No Cookie sent
- Application decision
- No identity decision
- The allowed values were selected
The application uses languages=[tr,en] and views=[compact,comfortable]. This branch selects the defaults en and comfortable when input is absent.
- Browser
- Awaiting result
- Preference handler
- language=en; view=comfortable
- Application decision
- No identity decision
- Preferences do not establish authority
Although language and layout are selected, the artifact establishes no login, role or tenant grant. A preference result cannot substitute for those decisions.
- Browser
- Awaiting result
- Preference handler
- Preference selection complete
- Application decision
- Presentation context only
- The presentation response is ready
The handler prepares the result for language en and layout comfortable. This response is neither an authentication document nor approval of a sensitive action.
- Browser
- Awaiting result
- Preference handler
- Preference result prepared
- Application decision
- Presentation context only
- The preference result reached the browser
The browser received the selected presentation result. Using defaults is a normal product branch; absence is not classified as an attack or failed login.
- Browser
- language=en; view=comfortable
- Preference handler
- Response prepared
- Application decision
- No identity decision
ASSUMPTION · BOUNDARY · CONTROL
Do not turn a preference into authority
The normal function is choosing language and layout. Its control restricts incoming values to two small allowed sets. Treating a cookie as an authority document because “the server wrote it earlier” gives client state excessive authority.
A preference-validation defect here can affect presentation or default selection. Using the same mechanism for a role or tenant decision has a different risk and requires server-owned identity and authorization policy. Derive impact from the decision consuming a value, not from the word cookie.
Automatic transmission does not remove application controls
A Browser-generated Cookie header does not prove that the user deliberately approved every request. Cookie state carries context to a subsequent operation; it does not independently establish intent or safety.
We do not portray this benign preference request as an authenticated action. A more sensitive action needs its own boundaries: input validation, identity resolution and resource/action policy. The WEB-11 Browser-security and WEB-14 authorization lessons develop those distinct controls.
3. Blue · Secure development & defense
Read every scenario without motion
Cookie source
- A preference observation was selected
Review starts with record pref-1. It uses cookiePresent and decision-source fields rather than copying raw Cookie values.
- Observation record
- requestId=pref-1; cookiePresent=true
- Branch comparison
- Not correlated
- Review conclusion
- No conclusion
- The decision source was read
The same observation records languageDecision=cookie and viewDecision=cookie. These fields belong to the application example, not a standard HTTP log schema.
- Observation record
- requestId=pref-1; cookiePresent=true
- Branch comparison
- languageDecision=cookie; viewDecision=cookie
- Review conclusion
- No conclusion
- The branch expectation was compared
The artifact with-preferences branch selects tr and compact. Review compares the decision source; browser appearance remains unproven.
- Observation record
- requestId=pref-1; cookiePresent=true
- Branch comparison
- Expected branch matches
- Review conclusion
- No conclusion
- The XPath selection was bounded
The XPath combining the default source with cookiePresent=false selects only pref-2. Not selecting pref-1 does not mean the record is absent.
- Observation record
- requestId=pref-1; cookiePresent=true
- Branch comparison
- XPath: not selected
- Review conclusion
- No conclusion
- UI evidence is requested separately
The observation shows the decision source. If the UI appears in a different language, matching cache, other state-source and rendering observations are needed; this record alone cannot explain the cause.
- Observation record
- requestId=pref-1; cookiePresent=true
- Branch comparison
- Decision source known
- Review conclusion
- UI outcome unknown
- The preference conclusion was preserved
The cookie/default decision can be explained for this branch. Authentication, actual browser cookie acceptance and rendered appearance require separate evidence.
- Observation record
- requestId=pref-1; cookiePresent=true
- Branch comparison
- Decision source: cookie
- Review conclusion
- No identity or UI evidence
Default source
- A preference observation was selected
Review starts with record pref-2. It uses cookiePresent and decision-source fields rather than copying raw Cookie values.
- Observation record
- requestId=pref-2; cookiePresent=false
- Branch comparison
- Not correlated
- Review conclusion
- No conclusion
- The decision source was read
The same observation records languageDecision=default and viewDecision=default. These fields belong to the application example, not a standard HTTP log schema.
- Observation record
- requestId=pref-2; cookiePresent=false
- Branch comparison
- languageDecision=default; viewDecision=default
- Review conclusion
- No conclusion
- The branch expectation was compared
The artifact without-preferences branch selects en and comfortable. Review compares the decision source; browser appearance remains unproven.
- Observation record
- requestId=pref-2; cookiePresent=false
- Branch comparison
- Expected branch matches
- Review conclusion
- No conclusion
- The XPath selection was bounded
The XPath combining the default source with cookiePresent=false selects only pref-2. Selecting pref-2 is not an attack finding.
- Observation record
- requestId=pref-2; cookiePresent=false
- Branch comparison
- XPath: pref-2 selected
- Review conclusion
- No conclusion
- UI evidence is requested separately
The observation shows the decision source. If the UI appears in a different language, matching cache, other state-source and rendering observations are needed; this record alone cannot explain the cause.
- Observation record
- requestId=pref-2; cookiePresent=false
- Branch comparison
- Decision source known
- Review conclusion
- UI outcome unknown
- The preference conclusion was preserved
The cookie/default decision can be explained for this branch. Authentication, actual browser cookie acceptance and rendered appearance require separate evidence.
- Observation record
- requestId=pref-2; cookiePresent=false
- Branch comparison
- Decision source: default
- Review conclusion
- No identity or UI evidence
IMPLEMENTATION · SECURITY CONTROL · VERIFICATION
Distinguish the sent header from the accepted record
Compare two Set-Cookie fields on the response, two records in cookie storage and pairs inside one Cookie field on the later request. These are not three copies of one screen. Policy evaluation separates response arrival from cookie acceptance, and later transmission is a fresh selection.
If a real Browser shows a blocked reason or scope mismatch, do not infer creation from the server response alone. The artifact includes an expected allowed path and a missing-cookie branch; it is neither a real HAR nor a Browser capture.
Observe preference decisions without carrying credentials
Our observation record has requestId, cookiePresent, languageDecision and viewDecision. These are fields in an application-owned example schema. Instead of copying the raw Cookie header into general logs, record only the constrained preference decision needed; the same header may later contain a session credential.
The XPath /observations/preferenceObservation[@cookiePresent="false" and @languageDecision="default"] selects only the default branch in the fixture XML. A benign missing-cookie case is not labelled an error or attack. A Turkish UI alongside a default observation with the same requestId invites investigation of another state source, cache or missing trace; it is not itself evidence of malicious intent.
Explain the control outcome together with its state source
Document allowed preference values, defaults and behavior under Browser privacy settings at the consuming endpoint. Verify the fallback when cookies are removed. Preserve the distinction between preferences and authenticated handles rather than applying one policy to every cookie class.
Success is not that preferences never disappear. The learner should explain whether the same page came from the cookie branch or default branch using headers, the jar and the application decision.
NOW APPLY IT TO THE CASE
Which decision does a cookie language preference carry?
Two small preference values are used in the cookie branch; defaults apply when they are absent. The scene separates preference source from identity and appearance evidence.
Which owner holds the case’s browser data? Explain why presence or deletion of a client value differs from the server-side session outcome.
Open the related case file ↗READ THE EXAMPLE TOGETHER
The response–jar–request trail of two preference cookies
Select a field and examine what it supports and where the evidence ends.
Read the raw artifact and field explanations
{
"host": "library.outreason.example",
"responseFields": [
"Set-Cookie: hd_language=tr; Path=/",
"Set-Cookie: hd_view=compact; Path=/"
],
"jarAfterArrival": [
{
"name": "hd_language",
"value": "tr",
"hostOnly": true,
"path": "/"
},
{
"name": "hd_view",
"value": "compact",
"hostOnly": true,
"path": "/"
}
],
"nextRequestFields": [
"Host: library.outreason.example",
"Cookie: hd_language=tr; hd_view=compact"
],
"applicationPolicy": {
"languages": [
"tr",
"en"
],
"views": [
"compact",
"comfortable"
],
"defaults": {
"language": "en",
"view": "comfortable"
}
},
"branches": [
{
"id": "with-preferences",
"cookiePresent": true,
"language": "tr",
"view": "compact",
"languageDecision": "cookie",
"viewDecision": "cookie"
},
{
"id": "without-preferences",
"cookiePresent": false,
"language": "en",
"view": "comfortable",
"languageDecision": "default",
"viewDecision": "default"
}
],
"observationXML": "<observations><preferenceObservation requestId=\"pref-1\" cookiePresent=\"true\" languageDecision=\"cookie\" viewDecision=\"cookie\"/><preferenceObservation requestId=\"pref-2\" cookiePresent=\"false\" languageDecision=\"default\" viewDecision=\"default\"/></observations>",
"localXPath": "/observations/preferenceObservation[@cookiePresent=\"false\" and @languageDecision=\"default\"]",
"expectedSelectedRequestIds": [
"pref-2"
]
}- responseFields
- Separate Set-Cookie fields per cookie, not one comma-separated field.
- jarAfterArrival
- Expected records after arrival and permitted Browser policy, not captured storage.
- nextRequestFields
- Transmitted name/value pairs without Path attributes.
- applicationPolicy / branches
- Preference allowlists and defaults, not authentication or book permissions.
- observationXML / localXPath
- Local selection over our synthetic XML, without network or temporal correlation.
Preferences are inert and secrets-free. The HTTP metadata is not a wire capture; the model does not run a cookie parser, Browser privacy engine or real endpoint. XPath selects only this XML fixture.
Two reality checks
A stateless HTTP site cannot remember an earlier selection.
Stateless protocol semantics do not forbid application state. Later-request data such as cookies and application records can provide continuity.
Set-Cookie and Cookie are two names for the same header.
Set-Cookie instructs Browser storage on a response; Cookie carries selected name/value pairs on a request without repeating attributes.
YOUR TURN
Work through this story.
Predict the outcome, find the evidence boundary, and explain it in your own words.
Which language/view values does the selected application choose when no Cookie is present?
- tr/compact; HTTP automatically treats the previous response as user state.
- en/comfortable; defaults.
Read the explained answer
en/comfortable; defaults. — The without-preferences branch applies application defaults when cookiePresent=false; HTTP does not independently remember prior choices.
Why are Set-Cookie and Cookie not two names for the same direction?
Selected lesson artifact fields; teaching example
- responseFields
- ["Set-Cookie: hd_language=tr; Path=/","Set-Cookie: hd_view=compact; Path=/"]
- nextRequestFields
- ["Host: library.outreason.example","Cookie: hd_language=tr; hd_view=compact"]
- Set-Cookie in a response proposes browser storage; Cookie in a subsequent request carries eligible values.
- The browser sends Set-Cookie as a request authorization header.
Read the explained answer
Set-Cookie in a response proposes browser storage; Cookie in a subsequent request carries eligible values. — Two separate Set-Cookie fields carry instructions for storing two preferences. In this example, the Browser creates the records after the response arrives and its cookie policy accepts them. The later request Cookie field carries only eligible name/value pairs.
hd_language=tr was stored in the browser. Why should the server evaluate the value against its languages allowlist?
Read the explained answer
A Cookie is browser-held request data; the application interprets values using its tr/en and compact/comfortable contract. Presence in the jar proves neither user authentication nor accepted business input. The application builds this state layer on top of stateless HTTP semantics.
□ I did not count browser storage as trusted policy.
□ I identified the owner of application defaults/allowlists.
Open the application console · request / response / browser
Also open request, URL, cookie and DOM examples
Sources and scope
- RFC 9110 — HTTP Semantics3.3 Connections, Clients, and Servers: stateless semantics
- RFC 6265 — HTTP State Management Mechanism3 Overview · 4.1 Set-Cookie · 4.2 Cookie · 4.2.2 Semantics
- MDN — Using HTTP cookiesWhat cookies are used for · Creating, removing, and updating cookies · Updating cookies via JavaScript
- MDN — Set-Cookie headerIntroduction: separate Set-Cookie headers and forbidden response header name · Syntax
- MDN — Cookie headerSyntax · Directives