Session Tokens
You are reading the documentation for version 2 of FoalTS. Instructions for upgrading to this version are available here. The old documentation can be found here.
#
IntroductionThis document assumes that you have alread read the Quick Start page.
In FoalTS, web sessions are temporary states that can be associated with a specific user. They are identified by a token and are mainly used to keep users authenticated between several HTTP requests (the client sends the token on each request to authenticate the user).
A session usually begins when the user logs in (or starts visiting the website) and ends after a period of inactivity or when the user logs out. By inactivity, we mean that the server no longer receives requests from the authenticated user for a certain period of time.
#
The Basics#
Choosing a session storeTo begin, you must first specify where the session states will be stored. FoalTS provides several session stores for this. For example, you can use the TypeORMStore
to save the sessions in your SQL database or the RedisStore
to save them in a redis cache.
To do so, the package name of the store must be provided with the configuration key settings.session.store
.
- YAML
- JSON
- JS
#
TypeORMStoreThis store uses the default TypeORM connection whose configuration is usually specified in ormconfig.{json|yml|js}
.
Session states are saved in the databasesession
table of your SQL database. In order to create it, you need to add and run migrations. For this purpose, you can export the DatabaseSession
entity in your user file and execute the following commands.
entities/user.entity.ts
Warning: If you use TypeORM store, then your entity IDs must be numbers (not strings).
#
RedisStoreIn order to use this store, you must provide the redis URI in the configuration.
- YAML
- JSON
- JS
#
MongoDBStoreThis store saves your session states in a MongoDB database (using the collection sessions
). In order to use it, you must provide the MongoDB URI in the configuration.
- YAML
- JSON
- JS
Authorization
header#
Usage with the This section explains how to use sessions with a
bearer
token and theAuthorization
header. See the section below to see how to use them with cookies.
The mechanism is as follows:
- Upon login, create the session and assign it to
ctx.session
. Then return the session token in the response. - On subsequent requests, send the token in the
Authorization
header with this scheme:Authorization: Bearer <token>
.
If the
Authorization
header does not use thebearer
scheme or if the token is invalid or expired, then the hook returns a 400 or 401 error.
If you want to make sure that ctx.session
is set and get a 400 error if no Authorization
header is provided, you can use the required
option for this.
#
Usage with cookiesThis section explains how to use sessions with cookies. See the section above to see how to use them with a
bearer
token and theAuthorization
header.
Be aware that if you use cookies, your application must provide a CSRF defense.
When using the @UseSessions
hook with the cookie
option, FoalTS makes sure that ctx.session
is always set and takes care of managing the session token on the client (using a cookie).
If the session has expired, the hook returns a 401 error. If you want to redirect the user to the login page, you can use the redirectTo
option to do so.
#
Adding authentication and access controlThis section explains how to associate a specific user to a session and how to use
ctx.user
.
Sessions can be used to authenticate users. To do this, you can use the Session.setUser
method and the fetchUser
function.
If you want to restrict certain routes to authenticated users, you can use the @UserRequired
hook for this.
If the user is not authenticated, the hook returns a 401 error. If you want to redirect the user to the login page, you can use the redirectTo
option to do so.
#
Reading user information on the clientThis feature is available from version 2.2 onwards.
When building a SPA with cookie-based authentication, it can sometimes be difficult to know if the user is logged in or to obtain certain information about the user (isAdmin
, etc).
Since the authentication token is stored in a cookie with the httpOnly
directive set to true
(to mitigate XSS attacks), the front-end application has no way of knowing if a user is logged in, except by making an additional request to the server.
To solve this problem, Foal provides an option called userCookie
that allows you to set an additional cookie that the frontend can read with the content you choose. This cookie is synchronized with the session and is refreshed at each request and destroyed when the session expires or when the user logs out.
In the following example, the user
cookie is empty if no user is logged in or contains certain information about him/her otherwise. This is particularly useful if you need to display UI elements based on user characteristics.
Server-side code
Cookies
Client-side code
#
Destroying the sessionSessions can be destroyed (i.e users can be logged out) using their destroy
method.
#
Save and Read ContentYou can access and modify the session content with the set
and get
methods.
#
Flash ContentSometimes we may wish to store items in the session only for the next request.
For example, when users enter incorrect credentials, they are redirected to the login page, and this time we may want to render the page with a specific message that says "Incorrect email or password". If the user refreshes the page, the message then disappears.
This can be done with flash content. The data will only be available on the next request.
#
Security#
Session Expiration TimeoutsSession states has two expiration timeouts.
Timeout | Description | Default value |
---|---|---|
Inactivity (or idle) timeout | Period of inactivity after which the session expires. | 15 minutes |
Absolute timeout | Period after which the session expires, regardless of its activity. | 1 week |
If needed, the default values can be override in the configuration. The timeouts must be provided in seconds.
- YAML
- JSON
- JS
#
Revoking Sessions#
Revoking One SessionOpen scripts/revoke-session.ts
and update its content.
Build the script.
Run the script.
#
Revoking All SessionsOpen scripts/revoke-all-sessions.ts
and update its content.
Build the script.
Run the script.
#
Query All Sessions of a UserThis feature is only available with the TypeORM store.
#
Query All Connected UsersThis feature is only available with the TypeORM store.
#
Force the Disconnection of a UserThis feature is only available with the TypeORM store.
#
Re-generate the Session IDWhen a user logs in or change their password, it is a good practice to regenerate the session ID. This can be done with the regenerateID
method.
#
Advanced#
Specify the Store LocallyBy default, the @UseSessions
hook and the Store
service retrieve the store to use from the configuration. This behavior can be override by importing the store directly into the code.
#
Cleanup Expired SessionsBy default, FoalTS removes expired sessions in TypeORMStore
and MongoDBStore
every 50 requests on average. This can be changed with this configuration key:
- YAML
- JSON
- JS
#
Implement a Custom StoreIf necessary, you can implement your own session store. This one must inherit the abstract class SessionStore
.
To use it, your can import it directly in your code (see the section Specify the Store Locally) or use a relative path in the configuration. In this case, the class must be exported with the name ConcreteSessionStore
.
Method | Description |
---|---|
save | Saves the session for the first time. If a session already exists with the given ID, a SessionAlreadyExists error MUST be thrown. |
read | Reads a session. If the session does not exist, the value null MUST be returned. |
update | Updates and extends the lifetime of a session. If the session no longer exists (i.e. has expired or been destroyed), the session MUST still be saved. |
destroy | Deletes a session. If the session does not exist, NO error MUST be thrown. |
clear | Clears all sessions. |
cleanUpExpiredSessions | Some session stores may need to run periodically background jobs to cleanup expired sessions. This method deletes all expired sessions. If the store manages a cache database, then this method can remain empty but it must NOT throw an error. |
Session stores do not manipulate Session
instances directly. Instead, they use SessionState
objects.
fetchUser
function#
Create a The function fetchUser
from the package @foal/typeorm
takes an @Entity()
class as parameter and returns a function with this signature:
If the ID matches a user, then an instance of the class is returned. Otherwise, the function returns undefined
.
If needed you can implement your own fetchUser
function with this exact signature.
#
Usage with Cookies#
Do not Auto-Create the SessionBy default, when the cookie
option is set to true, the @UseSessions
hook automatically creates a session if it does not already exist. This can be disabled with the create
option.
#
Override the Cookie OptionsThe default session cookie directives can be overridden in the configuration as follows:
- YAML
- JSON
- JS
#
Require the CookieIn rare situations, you may want to return a 400 error or redirect the user if no session cookie already exists on the client. If so, you can use the required
option to do so.
#
Read a Session From a TokenThe @UseSessions
hook automatically retrieves the session state on each request. If you need to manually read a session (for example in a shell script), you can do it with the readSession
function.
#
Save Manually a SessionThe @UseSessions
hook automatically saves the session state on each request. If you need to manually save a session (for example in a shell script), you can do it with the commit
method.