Webs_session
Session handling.
Sessions maintain state across request-response cycles. This module provides a basic mechanism to abstract session handlers.
A handler implementation using Webs_authenticated_cookie
s for storing session state on the clients is also provided.
module State : sig ... end
State descriptors.
module Handler : sig ... end
Session handlers.
type 'a response = 'a option * Webs.Http.Response.t
The type for session responses.
val setup :
'a State.t ->
('a, 'e) Handler.t ->
(('a option, 'e) Stdlib.result -> Webs.Http.Request.t -> 'a response) ->
Webs.Http.Request.t ->
Webs.Http.Response.t
setup sd h service
handles loading and saving state described by sd
with handler h
for service service
.
The resulting service behaves as follows. On a request r
, service
is invoked with the state loaded by h
for r
. The new state returned by service
is saved by h
if different from the loaded state.
This handler provides sessions by storing them on the client. The session data is unencrypted but authenticated, the client cannot tamper with it – unless it finds out about your private key.
This is convenient for small user state like login status as no state needs to be maintained on the server. However be mindful about the size of your state as it travels in each request and, on state changes, in responses.
The type for client stored load state errors.
val client_stored_error_message : client_stored_error -> string
client_stored_error_message e
is an english error message for e
.
val client_stored_error_string :
('a, client_stored_error) Stdlib.result ->
('a, string) Stdlib.result
client_stored_error_string r
is Result.map_error client_stored_error_message r
.
val client_stored :
private_key:Webs_authenticatable.Private_key.t ->
?attributes:Webs.Http.Cookie.attributes ->
name:string ->
unit ->
('a, client_stored_error) Handler.t
client_stored ~private_key ~atts ~name
stores non-expirable state on the client in an Webs_authenticated_cookie
authenticated with the private key private_key
, named name
and with attributes atts
atts
(defaults to Webs.Http.Cookie.default_attributes
).
Important. The default atts
has no path defined. This sets the cookie (and thus the session) only for the requested URI prefix which is unlikely to be what you want. FIXME cross-check that.
Warning. The state is not encrypted and stored on the client's matchine, make sure no service secrets are part of the state.
Warning. Cookies are set in the response iff the state changes in a request-response cycle. In particular this means that using a max_age
in the cookie attributes, will only refresh the deadline whenever the state changes; but we argue this should not be used anyways.
result
state injectionConvenience result combinators.
val for_result :
's option ->
('a, 'b) Stdlib.result ->
('s option * 'a, 's option * 'b) Stdlib.result
for_result st r
injects st
in either case of r
.
for_ok st r
injects st
into the error case of r
.
for_error st r
injects st
into the error case of r
.
TODO. Decide whether they makes sense.
FIXME. Revise this now that we have state load errors in the service, it brings new ways around this.
The session mechanism has no provision to automatically expire sessions. In general expiring sessions is not very user friendly, especially on mobile. It seems better to let the user have its state indefinitely if it wishes and have a sudo
-like mechanism that asks and provides elevated authentication for a limited amount of time to peform more sensitive operations.
This expiration mechanism can be devised on top of the mechanism of this module using session state itself – for example by having a sudo_until : Ptime.t option
field in the state of an authenticated cookie and dedicated logic to handle it.
Somehow it feels like a good separation of concerns, or not.
The State.t
type could be a heterogenous dictionary with serializable values. This makes state highly composable, but implicitely composable and thus harder to understand and audit.
For now we would rather try to explore how inconvenient explicit state design and composition is or becomes in practice.