dillonkearns / elm-pages / Server.SetCookie

Server-rendered pages in your elm-pages can set cookies. elm-pages provides two high-level ways to work with cookies:

Server.Session.withSession provides a high-level way to manage key-value pairs of data using cookie storage, whereas Server.Response.withSetCookieHeader gives a more low-level tool for setting cookies. It's often best to use the most high-level tool that will fit your use case.

You can learn more about the basics of cookies in the Web Platform in these helpful MDN documentation pages:


type alias SetCookie =
{ name : String
, value : String
, options : Options 
}

setCookie : String -> String -> Options -> SetCookie

Create a SetCookie record with the given name, value, and [Options](Options]. To add a Set-Cookie header, you can pass this value with Server.Response.withSetCookieHeader. Or for more low-level uses you can stringify the value manually with toString.

Building Options

Usually you'll want to start by creating default Options with options and then overriding defaults using the with... helpers.

import Server.SetCookie as SetCookie

options : SetCookie.Options
options =
    SetCookie.options
        |> SetCookie.nonSecure
        |> SetCookie.withMaxAge 123
        |> SetCookie.makeVisibleToJavaScript
        |> SetCookie.withoutPath
        |> SetCookie.setCookie "id" "a3fWa"


type alias Options =
{ expiration : Maybe Time.Posix
, visibleToJavaScript : Basics.Bool
, maxAge : Maybe Basics.Int
, path : Maybe String
, domain : Maybe String
, secure : Basics.Bool
, sameSite : Maybe SameSite 
}

The set of possible configuration options. You can configure this record directly, or use the with... helpers.

options : Options

Initialize the default SetCookie Options. Can be configured directly through a record update, or with withExpiration, etc.


type SameSite
    = Strict
    | Lax
    | None

Possible values for the cookie's same-site value.

The default option is Lax (Lax does not send cookies in cross-origin requests so it is a good default for most cases, but Strict is even more restrictive).

Override the default option using withSameSite.

withSameSite : SameSite -> Options -> Options

The default SameSite policy is Lax if one is not explicitly set. See the SameSite section in https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes.

withImmediateExpiration : Options -> Options

Sets Expires to Time.millisToPosix 0, which effectively tells the browser to delete the cookie immediately (by giving it an expiration date in the past).

makeVisibleToJavaScript : Options -> Options

The default option in this API is for HttpOnly cookies https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#httponly.

Cookies can be exposed so you can read them from JavaScript using Document.cookie. When this is intended and understood then there's nothing unsafe about that (for example, if you are setting a darkMode cookie and what to access that dynamically). In this API you opt into exposing a cookie you set to JavaScript to ensure cookies aren't exposed to JS unintentionally.

In general if you can accomplish your goal using HttpOnly cookies (i.e. not using makeVisibleToJavaScript) then it's a good practice. With server-rendered elm-pages applications you can often manage your session state by pulling in session data from cookies in a BackendTask (which is resolved server-side before it ever reaches the browser).

nonSecure : Options -> Options

Secure (only sent over https, or localhost on http) is the default. This overrides that and removes the Secure attribute from the cookie.

withDomain : String -> Options -> Options

Sets the Set-Cookie's Domain.

withExpiration : Time.Posix -> Options -> Options

withMaxAge : Basics.Int -> Options -> Options

Sets the Set-Cookie's Max-Age.

withPath : String -> Options -> Options

Sets the Set-Cookie's Path.

The default value is /, which will match any sub-directories or the root directory. See also `withoutPath

withoutPath : Options -> Options

If the server omits the Path attribute, the user agent will use the "directory" of the request-uri's path component as the default value.

Source: https://www.rfc-editor.org/rfc/rfc6265. See https://stackoverflow.com/a/43336097.

Internal

toString : SetCookie -> String

Usually you'll want to use Server.Response.withSetCookieHeader instead.

This is a low-level helper that's there in case you want it but most users will never need this.