!CHAPTER The Sessions App The sessions app provides a session storage JavaScript API that can be used in other Foxx apps. !SECTION Configuration This app has the following configuration options: * *timeToLive* (optional): number of milliseconds until the session expires. Default: *604800000* (one week). * *ttlType* (optional): attribute against which the *timeToLive* is enforced. Valid options: *lastAccess*, *lastUpdate*, *created*. Default: *"created"*. * *sidTimestamp* (optional): whether to append a timestamp to the random part of generated session IDs. Default: *false*. * *sidLength* (optional): number of random characters to use for new session IDs. Default *20*. !SECTION JavaScript API: *sessionStorage* This app exposes a session storage via a JavaScript API named *sessionStorage*. @EXAMPLES ```js var sessionStorage = Foxx.requireApp('/_system/sessions').sessionStorage; ``` !SUBSECTION Exceptions !SUBSUBSECTION Session Not Found Indicates a session could not be found in the database. `new sessionStorage.errors.SessionNotFound(sessionId)` Thrown by the session storage's *delete* and *get* methods if passed a session ID that does not exist in the database. @EXAMPLES ```js try { sessionStorage.get(invalidSessionId); } catch(err) { assertTrue(err instanceof sessionStorage.errors.SessionNotFound); } ``` !SUBSUBSECTION Session Expired Indicates the session exists in the database but has expired. `new sessionStorage.errors.SessionExpired(sessionId)` Thrown by the session storage's *get* method if passed a session ID for a session that has expired. See also this app's configuration options. @EXAMPLES ```js try { sessionStorage.get(expiredSessionId); } catch(err) { assertTrue(err instanceof sessionStorage.errors.SessionExpired); assertTrue(err instanceof sessionStorage.errors.SessionNotFound); } ``` !SUBSECTION The session object Session objects are instances of a Foxx model with the following attributes: * *sessionData*: volatile session data. This can be an arbitrary object that will be stored with the session in the database. If you want to store session-specific (rather than user-specific) data in the database, this is the right place for that. * *uid*: the session's active user's *_key* or *undefined* (no active user). * *userData*: the session's active user's *userData* attribute or an empty object. * *created*: timestamp the session was created at. * *lastAccess*: timestamp of the last time the session was fetched from the database. * *lastUpdate*: timestamp of the last time the session was written to the database. !SUBSECTION Create a session Creates and saves a new instance of the session model. `sessionStorage.create(sessionData)` *Parameter* * *sessionData* (optional): an arbitrary object that will be stored as the session's *sessionData* attribute when the model is saved to the database. @EXAMPLES ```js var session = sessionStorage.create(sessionData); assertEqual(session.get('sessionData'), sessionData); ``` !SUBSECTION Fetch an existing session There are two ways to fetch a session via the session storage API: * resolving a session cookie with the *fromCookie* method * calling the session storage's *get* method with a session ID directly !SUBSUBSECTION Resolve a session cookie Fetch a session matching a cookie in a Foxx request. `sessionStorage.fromCookie(request, cookieName, secret)` Parses a request's cookies and returns the matching instance of the session model. The method will return *null* instead of a session object in the following cases: * the request has no session cookie * the request's session cookie does not match a known session ID * the matching session has expired * the cookie's signature is missing (if a *secret* is provided) * the cookie's signature does not match (if a *secret* is provided) *Parameter* * *request*: a Foxx request object as passed to controller routes. * *cookieName*: name of the cookie to parse. * *secret* (optional): secret string to validate the cookie's signature with. @EXAMPLES ```js controller.get('/hello', function(request, response) { var session = sessionStorage.fromCookie(request, cookieName, secret); response.json(session.get('sessionData')); }); ``` !SUBSUBSECTION Resolve a session ID directly Fetch a session from the database for a given ID. `sessionStorage.get(sessionId)` Attempts to load the session with the given session ID from the database. If the session does not exist, a *SessionNotFound* exception will be thrown. If the session does exist, but has already expired, a *SessionExpired* exception will be thrown instead. *Parameter* * *sessionId*: a session *_key*. @EXAMPLES ```js var session = sessionStorage.get(sessionId); ``` !SUBSECTION Delete a session There are two ways to delete a session from the database: * calling the session storage's *delete* method with a session ID directly * telling a session to delete itself !SUBSUBSECTION Delete a session by its ID Delete a session with a given ID. `sessionStorage.delete(sessionId)` Attempts to delete the session with the given session ID from the database. If the session does not exist, a *SessionNotFound* exception will be thrown. The method always returns *null*. *Parameter* * *sessionId*: a session *_key*. @EXAMPLES ```js sessionStorage.delete(sessionId); ``` !SUBSUBSECTION Tell a session to delete itself Delete a session from the database. `session.delete()` Attempts to delete the session from the database. Returns *true* if the session was deleted successfully. Returns *false* if the session already didn't exist. @EXAMPLES ```js session.delete(); ``` !SUBSECTION Save a session Save a session to the database. `session.save()` If you made any changes to the session and are not using the sessions app via Foxx Authentication, you must call this method to commit the changes to the database. @EXAMPLES ```js session.setUser(user); session.save(); ``` !SUBSECTION Set a session's active user Set the active user of a session. `session.setUser(user)` Expects a Foxx model with a *userData* attribute and sets the session's *uid* attribute to the model's *_key* and the session's *userData* attribute to the model's *userData* attribute. *Parameter* * *user*: instance of a Foxx model with a *`userData* attribute. @EXAMPLES ```js session.setUser(user); assertEqual(session.get('uid'), user.get('_key')); assertEqual(session.get('userData'), user.get('userData')); ``` !SUBSECTION Add a session cookie to a response Add a session cookie to a Foxx response. `session.addCookie(response, cookieName, secret)` Adds a session cookie to the response. If a *secret* string is provided, the cookie is signed using that secret (a second cookie with the name *cookieName + '_sig'* containing the cryptographic signature of the cookie value is added to the response). If you want to use signed cookies, you must make sure to pass the same *secret* to the *fromCookie* method when fetching the session from a cookie later. *Parameter* * *response*: a Foxx response object as passed to controller routes. * *cookieName*: name of the cookie to parse. * *secret* (optional): secret string to sign the cookie with. @EXAMPLES ```js controller.get('/hello', function(request, response) { session.addCookie(response, cookieName, secret); }); ``` !SUBSECTION Clear a session cookie Clear the session cookie of a Foxx response. `session.clearCookie(response, cookieName, secret)` Adds a blank expired cookie to clear the user's previously set session cookie. If the method is passed a *secret* string, a second blank expired cookie is added that overwrites the signature cookie (see above). *Parameter* * *response*: a Foxx response object as passed to controller routes. * *cookieName*: name of the cookie to parse. * *secret* (optional): indicates the signature should be cleared also. @EXAMPLES ```js controller.get('/goodbye', function(request, response) { session.clearCookie(response, cookieName, secret); }); ```