# apostrophe-express

# Inherits from: apostrophe-module

This module initializes the Express framework, which Apostrophe uses and extends to implement both API routes and page-serving routes. The Express app object is made available as apos.app, and the express object itself as apos.express. You can add Express routes directly in your modules via apos.app.get, apos.app.post, etc., however be sure to also check out the route method available in all modules for a cleaner way to implement API routes. Adding routes directly to the Express app object is still sometimes useful when the URLs will be public.

This module also adds a number of standard middleware functions and implements the server side of CSRF protection for Apostrophe.

# Options

# baseUrl (GLOBAL OPTION, NOT SET FOR THIS SPECIFIC MODULE)

As a convenience, req.absoluteUrl is set to the absolute URL of the current request. If the baseUrl option at the top level, not for this specific module is set to a string such as http://mysite.com, any site-wide prefix and req.url are appended to that. Otherwise the absolute URL is constructed based on the browser's request. Setting the baseUrl global option is necessary for reasonable URLs when generating markup from a command line task.

# address

Apostrophe listens for connections on all interfaces (0.0.0.0) unless this option is set to another address.

In any case, if the ADDRESS environment variable is set, it is used instead.

# port

Apostrophe listens for connections on port 3000 unless this option is set to another port.

In any case, if the PORT environment variable is set, it is used instead.

# bodyParser

The json and urlencoded properties of this object are merged with Apostrophe's default options to be passed to the body-parser npm module's json and urlencoded flavors of middleware.

# prefix (a global option, not a module option)

This module implements parts of the sitewide prefix option, which is a global option to Apostrophe not specific to this module. If a prefix such as /blog is present, the site responds with its home page at /blog rather than /. All calls to res.redirect are adjusted accordingly, and supporting code in other modules adjusts AJAX calls made by jQuery as well, so that your code does not have to be "prefix-aware" in order to work.

# afterListen (a global option, not a module option)

If Apostrophe was configured with an afterListen option, that function is invoked after the site is ready to accept connections. An error will be passed if appropriate.

# session

Properties of the session option are passed to the express-session (opens new window) module. If each is not otherwise specified, Apostrophe enables these defaults:

{
  // Do not save sessions until something is stored in them.
  // Greatly reduces aposSessions collection size
  saveUninitialized: false,
  // The mongo store uses TTL which means we do need
  // to signify that the session is still alive when someone
  // views a page, even if their session has not changed
  resave: true,
  // Always update the cookie, so that each successive
  // access revives your login session timeout
  rolling: true,
  secret: 'you should have a secret',
  cookie: {
    path: '/',
    httpOnly: true,
    secure: false,
    // Default login lifetime between requests is one day
    maxAge: 86400000
  },
  store: (instance of connect-mongo/es5 provided by Apostrophe)
}

If you want to use another session store, you can pass an instance, but it's easier to let Apostrophe do the work of setting it up:

session: { store: { name: 'connect-redis', options: { // redis-specific options here } } }

Just be sure to install connect-redis, or the store of your choice, as an npm dependency.

# csrf

By default, Apostrophe implements Angular-compatible CSRF protection (opens new window) via an XSRF-TOKEN cookie. The apostrophe-assets module pushes a call to the browser to set a jQuery ajaxPrefilter which adds an X-XSRF-TOKEN header to all requests, which must match the cookie. This is effective because code running from other sites or iframes will not be able to read the cookie and send the header.

All non-safe HTTP requests (not GET, HEAD, OPTIONS or TRACE) automatically receive this proection via the csrf middleware, which rejects requests in which the CSRF token does not match the header.

If the csrf option is set to false, CSRF protection is disabled (NOT RECOMMENDED).

If the csrf option is set to an object, you can configure individual exceptions:

csrf: {
  exceptions: [ '/cheesy-post-route' ]
}

Exceptions may use minimatch wildcards (* and **). They can also be regular expression objects.

You may need to use this feature when implementing POST form submissions that do not use AJAX and thus don't send the header. We recommend using $.post or $.jsonCall for your forms, which eliminates this issue.

There is also a minimumExceptions option, which defaults to [ /login ]. The login form is the only non-AJAX form that ships with Apostrophe. XSRF protection for login forms is unnecessary because the password itself is unknown to the third party site; it effectively serves as an XSRF token.

You can also pass options to the Express res.cookie (opens new window) call that sets the cookie:

csrf: {
  exceptions: [ '/cheesy-post-route' ],
  cookie: {
    // Send it only if the request is HTTPS
    secure: true
  },
  // Disable storing a true random CSRF token in sessions for all site visitors.
  // Some protection is still provided via a well-known token and the Same Origin Policy.
  // Logged-in users always get a true random CSRF token in their session.
  // This setting is recommended because otherwise a session must be stored for
  // 100% of site accesses.
  disableAnonSession: true
}

Do not set the httpOnly flag as this will prevent legitimate same-origin JavaScript from adding it to requests.

# trustProxy

Enables the "trust proxy" option for Express (opens new window). Set to true to tell the Express app to respect X-Forwarded-* headers. This is helpful when Apostrophe is generating http: URLs even though a proxy like nginx is being used to serve it over https:.

# middleware

If a middleware array is present, those functions are added as Express middleware by the requiredMiddleware method, immediately after Apostrophe's standard middleware.

# Optional middleware: apos.middleware

This module adds a few useful but optional middleware functions to the apos.middleware object for your use where appropriate:

# apos.middleware.files

This middleware function accepts file uploads and makes them available via req.files. See the connect-multiparty (opens new window) npm module. This middleware is used by apostrophe-attachments.

# Module-specific middleware

In addition, this module will look for an expressMiddleware property in EVERY module. If such a property is found, it will be invoked as middleware on ALL routes, after the required middleware (such as the body parser) and before the configured middleware. If the property is an array, all of the functions in the array are invoked as middleware.

If expressMiddleware is a non-array object, it must have a middleware property containing a function or an array of functions, and it may also have a before property containing the name of another module. The function(s) in the middleware property will be run before those for the named module.

If you need to run the middleware very early, the object may also have a when property, which may be set to beforeRequired (the absolute beginning, before even req.body is available), afterRequired (after all middleware shipped with apostrophe-express but before all middleware passed to it as options), or afterConfigured (the default, with other module middleware).

# Methods

# createApp()

Create Apostrophe's apos.app and apos.express objects

# prefix()

Patch Express so that all calls to res.redirect honor the global prefix option without the need to make each call "prefix-aware"

# createData(req, res, next)

Standard middleware. Creates the req.data object, so that all code wishing to eventually add properties to the data object seen in Nunjucks templates may assume it already exists

# sessions()

Establish Express sessions. See options

# requiredMiddleware()

Install all standard middleware:

  • Create the req.data object on all requests
  • Implement Express sessions
  • Add the cookie parser
  • Angular-style CSRF protection
  • Extended body parser (req.body supports nested objects)
  • JSON body parser (useful with $.jsonCall)
  • Flash messages (see connect-flash (opens new window))
  • Internationalization (see apostrophe-i18n)
  • req.absoluteUrl always available (also see baseUrl)

# useModuleMiddleware(when)

Implement middleware added via self.expressMiddleware properties in modules.

# configuredMiddleware()

# enableCsrf()

Enable CSRF protection middleware. See compileCsrfExceptions for details on how to exclude a route from this.

# compileCsrfExceptions()

Compile CSRF exceptions, which may be regular expression objects or "minimatch" strings using the * and ** wildcards. They are taken from options.csrf.exceptions. /login, /password-reset and /password-reset-request are exceptions by default, which can be overridden via options.csrf.minimumExceptions. Also invokes the csrfExceptions Apostrophe event, passing the array of exceptions so it can be added to or otherwise modified by modules such as apostrophe-headless.

# csrf(req, res, next)

Angular-compatible CSRF protection middleware. On safe requests (GET, HEAD, OPTIONS, TRACE), set the XSRF-TOKEN cookie if missing. On unsafe requests (everything else), make sure our jQuery ajaxPrefilter set the X-XSRF-TOKEN header to match the cookie.

This works because if we're running via a script tag or iframe, we won't be able to read the cookie.

See the Angular docs for further discussion of this strategy. (opens new window)

# csrfWithoutExceptions(req, res, next)

See the csrf middleware method. This middleware method performs the actual CSRF check, without checking for exceptions first. It does check for and allow safe methods. This method is useful when you have made your own determination that this URL should be subject to CSRF.

# optionalMiddleware()

Establish optional middleware functions as properties of the apos.middleware object. Currently just apos.middleware.files.

# addListenMethod()

Establish the apos.listen method, which Apostrophe will invoke at the end of its initialization process.

# apostropheDestroy(callback)

Invoked by callAll when apos.destroy is called. Destroys the HTTP server object, freeing the port.

# absoluteUrl(req, res, next)

Standard middleware. Sets the req.absoluteUrl property for all requests, based on the baseUrl option if available, otherwise based on the user's request headers. The global prefix option and req.url are then appended.

req.baseUrl and req.baseUrlWithPrefix are also made available, and all three properties are also added to req.data if not already present.

The baseUrl option should be configured at the top level, for Apostrophe itself, NOT specifically for this module, but for bc the latter is also accepted in this one case. For a satisfyingly global result, set it at the top level instead.

# htmlPageId(req, res, next)

Makes the Apostrophe-Html-Page-Id header available as req.htmlPageId. This header is passed by all jQuery AJAX requests made by Apostrophe. It contains a unique identifier just for the current webpage in the browser; that is, navigating to a new page always generates a new id, the same page in two tabs will have different ids, etc. This makes it easy to identify requests that come from the "same place" for purposes of conflict resolution and locking. (Note that conflicts can occur between two tabs belonging to the same user, so a session ID is not enough.)

# addAbsoluteUrlsToReq(req)

Sets the req.absoluteUrl property for all requests, based on the baseUrl option if available, otherwise based on the user's request headers. The global prefix option and req.url are then appended.

req.baseUrl and req.baseUrlWithPrefix are also made available, and all three properties are also added to req.data if not already present.

The baseUrl option should be configured at the top level, for Apostrophe itself, NOT specifically for this module, but for bc the latter is also accepted in this one case. For a satisfyingly global result, set it at the top level instead.

If you want reasonable URLs in req objects used in tasks you must set the baseUrl option for Apostrophe.

# afterInit()

Locate modules with middleware and add it to the list. Also compile the CSRF exceptions, late, so that other modules can respond to the csrfExceptions event.

# findModuleMiddleware()

Locate modules with middleware and add it to the list