Skip to content

Instantly share code, notes, and snippets.

Last active November 4, 2019 15:31
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
ColdFusion SetCookie UDF to add support for samesite
<!--- 9/15/2010 Original:
<cfset SetCookie(name="logintoken", value="sometoken", secure=true, httponly=true, samesite="strict")>
11/1/2019 Updated to add support for encodevalue, preserveCase & samesite
Results in double cookie headers being added to HTTP response, but 2nd cookie header overwrites 1st cookie header
and variable is properly added to CF cookie scope.
WARNING: If any content is flushed, headers can't be added & error is thrown (I have workaround, but it's specific to ACF) --->
<cffunction name="SetCookie" hint="Replacement for cfcookie that handles httponly and samesite cookies" output="no" returntype="void">
<cfargument name="name" type="string" required="true">
<cfargument name="value" type="string" required="true">
<cfargument name="expires" type="any" default="" hint="''=session only|now|never|[date]|[number of days]">
<cfargument name="secure" type="boolean" default="false">
<cfargument name="path" type="string" default="/">
<cfargument name="domain" type="string" default="">
<cfargument name="httponly" type="boolean" default="false">
<cfargument name="encodevalue" type="boolean" default="true">
<cfargument name="preserveCase" type="boolean" default="false">
<cfargument name="samesite" type="string" default=""><!--- None, Strict, Lax --->
<cfset var cookieData = []>
<cfset var expDate = "">
<cfif isValid("boolean", Arguments.PreserveCase) AND Arguments.PreserveCase>
<!--- nothing --->
<cfset Arguments.Name = UCase(Arguments.Name)>
<cfif isvalid("boolean", arguments.encodeValue) AND arguments.encodevalue>
<cfset arrayAppend(cookieData, "")>
<cfset arrayAppend(cookieData, """#replace(argumments.value,'"','\"')#""")>
<cfset arrayAppend(cookieData, "Version=1")>
<cfswitch expression="#Arguments.expires#">
<cfcase value=""></cfcase>
<cfcase value="now"><cfset expDate = DateAdd("d",-1,Now())></cfcase>
<cfcase value="never"><cfset expDate = DateAdd("yyyy",30,Now())></cfcase>
<cfcase value="session"><cfset expDate = ""></cfcase>
<cfif IsDate(Arguments.expires)>
<cfset expDate = Arguments.expires>
<cfelseif IsNumeric(Arguments.expires)>
<cfset expDate = DateAdd("d",Arguments.expires,Now())>
<cfif isValid("date", expDate)>
<cfset expDate = DateConvert("local2Utc",expDate)>
<cfset ArrayAppend(cookieData, "expires=#DateFormat(expDate, 'ddd, dd mmm yyyy')# #TimeFormat(expDate, 'HH:mm:ss')# -0000")>
<cfif Len(Arguments.domain)>
<cfset ArrayAppend(cookieData, "domain=#Arguments.domain#")>
<cfif Len(Arguments.path)>
<cfset ArrayAppend(cookieData, "path=#Arguments.path#")>
<cfset ArrayAppend(cookieData, "SECURE")>
<cfif Arguments.httponly>
<cfset ArrayAppend(cookieData, "HttpOnly")>
<cfif ListFindNoCase("none,strict,lax", Arguments.samesite)>
<cfset ArrayAppend(cookieData, "SameSite=#Arguments.samesite#")>
<!--- generate cfcookie (using params that it allows) --->
<cfif not len(arguments.expires)>
<cfset structDelete(arguments, "expires")>
<cfset structDelete(arguments, "samesite")>
<cfif isDefined("Server.ColdFusion.ProductVersion")>
<cfif Val(ListFirst(Server.ColdFusion.ProductVersion)) LT 9>
<cfset structDelete(arguments, "httponly")>
<cfif Val(ListFirst(Server.ColdFusion.ProductVersion)) LT 10>
<cfset structDelete(arguments, "encodevalue")>
<cfset structDelete(arguments, "preserveCase")>
<cfcookie attributecollection="#arguments#">
<!--- follow it up with corrected cookie header --->
<cfheader name="Set-Cookie" value="#ArrayToList(cookieData, '; ')#">
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment