SameSite cookie attribute not being set
Favo02 opened this issue · comments
Hello, thanks for the beautiful library!
I am developing a REST API, sending some responses with Set-Cookie header, using Opium.Response.add_cookie_or_replace
function.
I'd like to set the SameSite
cookie attribute, but the ~same_site:
optional parameter doesn't do the job. I tried setting it to `Strict
, `Lax
and `None
but the cookie always shows None
.
This is the piece of code I am using:
let set_cookie
?(cookie_key = "_session")
?(secret = Sihl.Configuration.read_secret ())
?(max_age = 3600L)
?(scope = "/")
?(same_site = "strict")
?(http_only = true)
session
resp
=
let signed_with = Opium.Cookie.Signer.make secret in
let session = session |> List.to_seq |> StrMap.of_seq in
let cookie_value = to_json session in
let cookie = cookie_key, cookie_value in
let same_site = match same_site with | "strict" -> `Strict | "lax" -> `Lax | _ -> `None in
Opium.Response.add_cookie_or_replace
~sign_with:signed_with
~expires:(`Max_age max_age)
~scope:(Uri.of_string scope)
~same_site:same_site
~secure:true
~http_only:http_only
cookie
resp
I also tried a much simpler, unsuccessful:
let set_cookie session resp =
Opium.Response.add_cookie_or_replace
~same_site:`Strict
session
resp
The problem seems to be in Cookie.to_set_cookie_header
function, which simply ignores same site attribute.
I prepared a PR #291 to fix the issue, simply adding it.
let to_set_cookie_header t =
let v = Printf.sprintf "%s=%s" (fst t.value) (snd t.value) in
let v =
match Uri.path t.scope with
| "" -> v
| path -> Printf.sprintf "%s; Path=%s" v path
in
let v =
match Uri.host t.scope with
| None -> v
| Some domain -> Printf.sprintf "%s; Domain=%s" v domain
in
+ let v =
+ match t.same_site with
+ | `None -> Printf.sprintf "%s; SameSite=None" v
+ | `Strict -> Printf.sprintf "%s; SameSite=Strict" v
+ | `Lax -> Printf.sprintf "%s; SameSite=Lax" v
+ in
let v =
match t.expires with
| `Date ptime ->
Printf.sprintf "%s; Expires=%s" v (Ptime.to_date_time ptime |> Date.serialize)
| `Max_age max -> Printf.sprintf "%s; Max-Age=%s" v (Int64.to_string max)
| `Session -> v
in
let v = if t.secure then Printf.sprintf "%s; Secure" v else v in
let v = if t.http_only then Printf.sprintf "%s; HttpOnly" v else v in
"Set-Cookie", v
;;