Sessions

Managing sessions in naboris.

# Session Data

Many Naboris types take the parameter 'sessionData this represents a custom data type that will define session data that will be attached to an incoming request.

# Session Config

ServerConfig.setSessionConfig will return a new server configuration with the desired session configuration. This call consists of one required argument mapSession and three optional arguments ~maxAge, ~sidKey, and ~secret.

1let setSessionConfig: (~maxAge: int=?, ~sidKey: string=?, ~secret: string=?, option(string) => Lwt.t(option(Session.t('sessionData))), ServerConfig.t('sessionData)) => ServerConfig.t('sessionData);
1val setSessionConfig: ?maxAge: int -> ?sidKey: string -> ?secret: string -> string option -> 'sessionData Session.t option Lwt.t -> 'sessionData ServerConfig.t -> 'sessionData ServerConfig.t
  • sidKey - string (optional) - The key used to store the session id in browser cookies. Defaults to "nab.sid".
  • maxAge - int (optional) - The max age of session cookies in seconds. Defaults to 2592000 (30 days).
  • secret - string (optional) - A secret string used to sign session id cookies.
  • mapSession - covered in the section below.

# Session Mapping

mapSession is a special function that is used to set session data on an incoming request based on the requests cookies. The signature looks like: option(string) => Lwt.t(option(Naboris.Session.t('sessionData))). That's a complicated type signature that expresses that the request may or may not have a sessionId; and given that fact it may or may not return a session.

1// ReasonML
2// Your custom data type
3type userData = {
4  userId: int,
5  username: string,
6  firstName: string,
7  lastName: string,
8  isAdmin: bool,
9};
10
11let serverConfig: Naboris.ServerConfig(userData) = Naboris.ServerConfig.create()
12  |> Naboris.ServerConfig.setSessionConfig(sessionId => switch(sessionId) {
13    | Some(id) =>
14      /* for the sake of this example we're not using ppx or infix */
15      /* lwt promises can be made much easier to read by using these */
16      Lwt.bind(getUserDataById(id),
17        userData => {
18          let session = Naboris.Session.create(id, userData);
19          Lwt.return(Some(session));
20        }
21      );
22    | None => Lwt.return(None);
23  })
24  |> Naboris.ServerConfig.setRequestHandler((route, req, res) => switch(Naboris.Route.meth(meth), Naboris.Route.path(route)) {
25    | (Naboris.Method.POST, ["login"]) =>
26      let (req2, res2, _sessionId) =
27        /* Begin a session */
28        Naboris.SessionManager.startSession(
29          req,
30          res,
31          {
32            userId: 1,
33            username: "foo",
34            firstName: "foo",
35            lastName: "bar",
36            isAdmin: false,
37          },
38        );
39        Naboris.Res.status(200, res2) |> Naboris.Res.text(req2, "OK");
40    | (Naboris.Method.GET, ["who-am-i"]) =>
41      /* Get session data from the request */
42      switch (Naboris.Req.getSessionData(req)) {
43      | None =>
44        Naboris.Res.status(404, res) |> Naboris.Res.text(req, "Not found")
45      | Some(userData) =>
46        Naboris.Res.status(200, res)
47        |> Naboris.Res.text(req, userData.username)
48      };
49  });
1(* OCaml *)
2(* Your custom session data *)
3type user_data = {
4  userId: int;
5  username: string;
6  first_name: string;
7  last_name: string;
8  is_admin: bool
9}
10
11let serverConfig: user_data Naboris.ServerConfiguserData = Naboris.ServerConfig.create ()
12  |> Naboris.ServerConfig.setSessionConfig (fun session_id ->
13    match (session_id) with
14      | Some(id) =>
15        (* for the sake of this example we're not using ppx or infix *)
16        (* lwt promises can be made much easier to read by using these *)
17        Lwt.bind (get_user_data_by_id id) (fun user_data ->
18          let session = Naboris.Session.create id user_data in
19	  Lwt.return Some(session)
20        )
21    | None => Lwt.return None)
22  |> Naboris.ServerConfig.setRequestHandler (fun route, req, res ->
23    match ((Naboris.Route.meth route), (Naboris.Route.path route)) with
24      | (Naboris.Method.POST, ["login"]) ->
25        let (req2, res2, _session_id) =
26        (* Begin a session *)
27          Naboris.SessionManager.startSession req res {
28            userId= 1;
29            username= "foo";
30            first_name= "foo";
31            last_name= "bar";
32            is_admin= false
33          } in
34        Naboris.Res.status 200 res2
35          |> Naboris.Res.text req2, "OK"
36    | (Naboris.Method.GET, ["who-am-i"]) ->
37      (* Get session data from the request *)
38      match (Naboris.Req.getSessionData req) with
39        | None ->
40          Naboris.Res.status 404 res
41            |> Naboris.Res.text req "Not found"
42        | Some(user_data) ->
43          Naboris.Res.status 200 res
44            |> Naboris.Res.text req user_data.username)

# Starting Sessions

SessionManager.startSession generates a new session id string value and adds Set-Cookie header to a new Res.t. Useful for handling a login request.

1let startSession: (Req.t('sessionData), Res.t, 'sessionData) => (Req.t('sessionData), Res.t, string);
1val startSession: 'sessionData Req.t -> Res.t -> 'sessionData -> 'sessionData Req.t * Res.t * string

An example login request might look like this:

1| (Naboris.Method.POST, ["login"]) =>
2  let (req2, res2, _sid) =
3    Naboris.SessionManager.startSession(
4      req,
5      res,
6      TestSession.{username: "realsessionuser"},
7    );
8  Naboris.Res.status(200, res2) |> Naboris.Res.text(req2, "OK");
1| (Naboris.Method.POST, ["login"]) ->
2  let (req2, res2, _sid) = Naboris.SessionManager.startSession
3    req
4    res
5    TestSession.{username= "realsessionuser"} in
6  (Naboris.Res.status 200 res2) |> Naboris.Res.text req2 "OK"

# Invalidate Sessions

SessionManager.removeSession adds Set-Cookie header to a new Res.t to expire the session id cookie. Useful for handling a logout request.

1let removeSession: (Req.t('sessionData), Res.t) => Res.t;
1val removeSession: 'sessionData Req.t -> Res.t -> Res.t

An example logout request might look like this:

1| (Naboris.Method.GET, ["logout"]) =>
2  Naboris.SessionManager.removeSession(req, res)
3    |> Naboris.Res.status(200)
4    |> Naboris.Res.text(req, "OK");
1| (Naboris.Method.GET, ["logout"]) ->
2  Naboris.SessionManager.removeSession req res
3    |> Naboris.Res.status 200
4    |> Naboris.Res.text req "OK";
Support us on GitHub

Star, follow, fork

Star Fork

Found a typo? a bug? or something that just doesn't make any sense? Help improve these docs by opening a github issue.

naboris source code is licensed MIT.
It can be used, copied, and modified free of charge. However, the software is provided "as is" without any warranties. Click the link above for more information.