DevLearningTools

MODULE 8 · LESSON 07

Cookies

Setting and reading cookies in ColdFusion — the Cookie scope vs the <cfcookie> tag, the counter-intuitive domain gotcha, security attributes, and how ColdFusion uses CFID/CFToken cookies internally.

New lessons are added one at a time as the course gets built out — a graded quiz for each lesson is still on the way.

A cookie is a small piece of data a server asks a browser to store, which the browser then sends back automatically on every later request to that same site. They're how a site remembers something about a visitor between separate visits, days or weeks apart, without needing them to log in every time.

A simple, real example: remembering that a visitor chose a dark theme, so the site opens in dark mode the next time they show up, without them having to set it again.

Learning Objectives

After completing this lesson, you'll be able to:

  • Set and read a cookie using both the Cookie scope and the <cfcookie> tag.
  • Explain the real difference between the two, and when each one is the right choice.
  • Avoid the counter-intuitive domain gotcha that catches almost everyone once.
  • Use the secure, httpOnly, and sameSite attributes to keep a cookie safe.

The Simplest Way: The Cookie Scope

Assigning directly into the cookie scope sends a simple cookie to the browser — no expiration date set means it disappears when the browser closes.

CFScript — Setting
<cfscript>

cookie.theme = "dark";

</cfscript>
Tag Syntax — Setting
<cfset cookie.theme = "dark">
CFScript — Reading
Simulated output — illustrative only, not a live ColdFusion/Lucee server.
Tag Syntax — Reading
Simulated output — illustrative only, not a live ColdFusion/Lucee server.
NOTE

Cookie names are uppercased by default (cookie.theme is really stored as THEME) — cookie scope lookups are case-insensitive, so this usually doesn't matter until you need preserveCase.

Full Control: The <cfcookie> Tag

The Cookie scope is fine for a simple, short-lived cookie. For anything that needs to survive longer than the current browser session, or needs specific security settings, use <cfcookie> instead — it's the only way to control expiration, domain, path, and the security attributes.

CFScript
<cfscript>

cfcookie(
    name = "theme",
    value = "dark",
    expires = 365,       // days
    httponly = true,
    samesite = "Lax"
);

</cfscript>
Tag Syntax
<cfcookie
    name="theme"
    value="dark"
    expires="365"
    httponly="true"
    samesite="Lax">

cfcookie Attributes

AttributePurpose
name / valueThe cookie's name and value — required
expiresA number of days, a date, "now" (deletes the cookie), or "never" (~30-year expiration). Omitted = expires when the browser closes
secureOnly sent over HTTPS when true
httponlyBlocks JavaScript (document.cookie) from reading it when true — a real XSS mitigation
samesite"Strict", "Lax", or "None" — controls whether it's sent on cross-site requests
domainWhich domain the cookie is valid for — see the gotcha below
pathRestricts the cookie to a specific URL path, e.g. "/account"
preserveCaseKeep the cookie's name exactly as written, instead of uppercasing it (default false)

The Domain Gotcha: Leaving It Out Makes a Cookie MORE Restrictive

This one surprises almost everyone the first time: skipping the domain attribute doesn't make a cookie more broadly available — it does the opposite. A cookie set without a domain is locked to the exact host that set it. A cookie set on app.example.com without a domain won't be sent to api.example.com, even though they're both subdomains of the same site.

To share a cookie across subdomains, set domain explicitly to the shared parent, starting with a leading period.

CFScript
<cfscript>

// only valid on the exact host that set it
cfcookie(name = "theme", value = "dark");

// valid on app.example.com, api.example.com, anything.example.com
cfcookie(name = "theme", value = "dark", domain = ".example.com");

</cfscript>
NOTE

You can only set a cookie for a domain that's actually part of the current request's URL — a page on example.com can't set a cookie for a completely unrelated domain.

Reading a Cookie by a Dynamic Name

If the cookie's name is only known at runtime (stored in a variable), dot notation doesn't work — use bracket notation instead, the same pattern that works on any CFML scope.

CFScript
Simulated output — illustrative only, not a live ColdFusion/Lucee server.

How ColdFusion Uses Cookies Internally

ColdFusion sets its own cookies behind the scenes to make Session and Client scope work at all: CFID (a sequential client identifier) and CFTOKEN (a random security token) by default, or jsessionid instead if J2EE session management is enabled. These are what let ColdFusion recognize the same visitor across separate requests.

If a visitor has cookies disabled, these can't be set — Adobe's own guidance is direct about the consequence: don't rely on Client variables if you need to support visitors with cookies disabled, since the fallback (passing CFID/CFTOKEN through the URL) makes client data behave like session data that never gets cleaned up.

Common Beginner Mistakes

Expecting a cookie set without domain to work across subdomains

It's the opposite of what most people expect — omitting domain makes a cookie host-only. Set domain explicitly (with a leading period) to share it across subdomains.

Reading cookie.someName without checking it exists first

If the cookie was never set (first-time visitor, or it expired), this throws an error rather than returning an empty value. Always structKeyExists(cookie, "name") first.

Using the Cookie scope when the cookie needs to survive after the browser closes

Cookie-scope assignments don't set an expiration — they vanish when the browser closes. Use <cfcookie> with an explicit expires value for anything that needs to persist.

Storing sensitive data in a cookie without httponly

Without httponly=true, any JavaScript running on the page (including injected via XSS) can read the cookie's value through document.cookie.

Best Practices

  • Use <cfcookie> instead of the Cookie scope whenever you need a specific expiration, domain, or security setting.
  • Set httponly=true on any cookie that doesn't specifically need to be read by client-side JavaScript.
  • Set secure=true for any cookie carrying anything sensitive, so it's never sent over plain HTTP.
  • Never store passwords, tokens, or anything sensitive directly in a cookie's value — cookies are visible to the visitor and can be tampered with client-side.

Interview Questions

What's the difference between setting a cookie via the Cookie scope vs <cfcookie>?

The Cookie scope is quick but limited to a simple session cookie with no explicit expiration or security attributes. <cfcookie> gives full control over expiration, domain, path, secure, httponly, and samesite.

What happens if you don't set the domain attribute on a cookie?

The cookie becomes host-only — restricted to the exact domain that set it, and won't be sent to other subdomains of the same site. This is the opposite of what most people assume.

What does httponly actually protect against?

It prevents client-side JavaScript from reading the cookie via document.cookie, which limits what an XSS vulnerability could steal even if one exists on the page.

What are CFID and CFTOKEN?

Cookies ColdFusion sets automatically to identify a visitor across requests, which is what makes Session and Client scope possible. If J2EE session management is used instead, a jsessionid cookie is used in their place.

Summary

In this lesson, you set and read cookies with both the Cookie scope and <cfcookie>, covered the counter-intuitive domain restriction, dynamic cookie name access, the security attributes, and how ColdFusion's own CFID/CFTOKEN cookies make Session and Client scope work.

What's Next?

The next lesson covers Client Variables — data that persists across a visitor's separate visits, similar to cookies but with more storage options (database, registry) and a longer natural lifespan.