Skip to content

Sessions

Sessions allow you to persist a user's data between multiple requests. Sessions work by creating and returning a unique cookie alongside the HTTP response when a new session is initialized. Browsers will automatically detect this cookie and include it in future requests. This allows Vapor to automatically restore a specific user's session in your request handler.

Sessions are great for front-end web applications built in Vapor that serve HTML directly to web browsers. For APIs, we recommend using stateless, token-based authentication to persist user data between requests.

Configuration

To use sessions in a route, the request must pass through SessionsMiddleware. The easiest way to achieve this is by adding this middleware globally. It is recommended that you do add this after you declare the cookie factory. This is because Sessions is a struct, therefore it is a value type, and not a reference type. Since it is a value type, you must set the value before using SessionsMiddleware.

app.middleware.use(app.sessions.middleware)

If only a subset of your routes utilize sessions, you can instead add SessionsMiddleware to a route group.

let sessions = app.grouped(app.sessions.middleware)

The HTTP cookie generated by sessions can be configured using app.sessions.configuration. You can change the cookie name and declare a custom function for generating cookie values.

// Change the cookie name to "foo".
app.sessions.configuration.cookieName = "foo"

// Configures cookie value creation.
app.sessions.configuration.cookieFactory = { sessionID in
    .init(string: sessionID.string, isSecure: true)
}

app.middleware.use(app.sessions.middleware)

By default, Vapor will use vapor_session as the cookie name.

Drivers

Session drivers are responsible for storing and retrieving session data by identifier. You can create custom drivers by conforming to the SessionDriver protocol.

Warning

The session driver should be configured before adding app.sessions.middleware to your application.

In-Memory

Vapor utilizes in-memory sessions by default. In-memory sessions require zero configuration and do not persist between application launches which makes them great for testing. To enable in-memory sessions manually, use .memory:

app.sessions.use(.memory)

For production use cases, take a look at the other session drivers which utilize databases to persist and share sessions across multiple instances of your app.

Fluent

Fluent includes support for storing session data in your application's database. This section assumes you have configured Fluent and can connect to a database. The first step is to enable the Fluent sessions driver.

import Fluent

app.sessions.use(.fluent)

This will configure sessions to use the application's default database. To specify a specific database, pass the database's identifier.

app.sessions.use(.fluent(.sqlite))

Finally, add SessionRecord's migration to your database's migrations. This will prepare your database for storing session data in the _fluent_sessions schema.

app.migrations.add(SessionRecord.migration)

Make sure to run your application's migrations after adding the new migration. Sessions will now be stored in your application's database allowing them to persist between restarts and be shared between multiple instances of your app.

Redis

Redis provides support for storing session data in your configured Redis instance. This section assumes you have configured Redis and can send commands to the Redis instance.

To use Redis for Sessions, select it when configuring your application:

import Redis

app.sessions.use(.redis)

This will configure sessions to use the Redis sessions driver with the default behavior.

Seealso

Refer to Redis → Sessions for more detailed information about Redis and Sessions.

Session Data

Now that sessions are configured, you are ready to persist data between requests. New sessions are initialized automatically when data is added to req.session. The example route handler below accepts a dynamic route parameter and adds the value to req.session.data.

app.get("set", ":value") { req -> HTTPStatus in
    req.session.data["name"] = req.parameters.get("value")
    return .ok
}

Use the following request to initialize a session with the name Vapor.

GET /set/vapor HTTP/1.1
content-length: 0

You should receive a response similar to the following:

HTTP/1.1 200 OK
content-length: 0
set-cookie: vapor-session=123; Expires=Fri, 10 Apr 2020 21:08:09 GMT; Path=/

Notice the set-cookie header has been added automatically to the response after adding data to req.session. Including this cookie in subsequent requests will allow access to the session data.

Add the following route handler for accessing the name value from the session.

app.get("get") { req -> String in
    req.session.data["name"] ?? "n/a"
}

Use the following request to access this route while making sure to pass the cookie value from the previous response.

GET /get HTTP/1.1
cookie: vapor-session=123

You should see the name Vapor returned in the response. You can add or remove data from the session as you see fit. Session data will be synchronized with the session driver automatically before returning the HTTP response.

To end a session, use req.session.destroy. This will delete the data from the session driver and invalidate the session cookie.

app.get("del") { req -> HTTPStatus in
    req.session.destroy()
    return .ok
}