Skip to main content
important

This is a contributors guide and NOT a user guide. Please visit these docs if you are using or evaluating SuperTokens.

Overview

The core service is a Java based http service that is stateless and concurrently safe.

By stateless, we mean that one can spin several instances of the core and sending a request to any one of them is alway identical to sending the same request to another one of them.

By concurrently safe, we mean that it is thread safe, as well as multi-process safe. This means that if an operation is not idempotent (like signing up a new user based on their email), doing that operation in parallel across different cores should have the same effect that these operations were instead run in a sequence. This in turn implies that we will have to use mutex locking with a core, or db transactions (with row level locking), or some concensus algorithm, or some distributed locking system.

Bootup#

The following operations happen when the core is started:

  • Loading and applying the CLI options into memory
  • Registering a callback to handle the kill signal for the core
  • Initialising the storage layer based on the db plugin that's available and the user config (or using an in memory db)
  • Loading core configs
  • Loading the version file (in case the core business logic needs it)
  • Initialise logging (info and error logging)
  • Starting Cronjobs
  • Creating the storage layer tables if needed
  • Starting the webserver
  • Mark this process as started (so that the CLI can know that this is running).

User configuration#

User config is given via a config.yaml which is to be located in core's installation directory.

On bootup, this config file is loaded and checked for errors (like ranges of values). If there is an error, of if the file is missing, then the core doesn't start.

There is also a devConfig.yaml file which is used when running the core during development / testing.

The overall config file is made up of two config files:

  • One from the supertokens-core's config.yaml file: This contains all the configs specific to the core's setting.
  • Other from supertokens-DB_NAME-plugin's config.yaml file: This contains all the configs specific to the database's setting - like the db connection info.

When running using docker, the configs can be passed as env vars in the docker run command as well. Those are then copied into the config file when the docker image starts and the core service reads from the config file as usual.

Some configs are in the core, whilst most others are in the backend / frontend SDKs. We aim to put the configs in the backend / frontend SDKs whenever possible, since that is easier for users to set. However sometimes, (like if a cronjob in the core is accessing a config value), it would need to be in the core's config.yaml.

Webserver#

We use an embedded apache tomcat server. The code for this can be seen here.

Each API we make extends a base class - WebserverAPI.java which takes care of some checks like:

  • CDI version compatibility
  • API key check
  • Logging success / failure

Finally, each recipe has their own directory of APIs in here.

Cronjobs#

Cronjobs are background processes that run every specific interval of time. They are started during bootup using the Cronjobs.java singleton class.

When implementing a cronjob, you need to specify:

  • The initial wait time
  • The interval time between cronjob runs
  • The body of the cronjob

This is an example cronjob that clears expired sessions.

Any exceptions thrown from a cronjob are logged, and then ignored.

Recipes#

Each recipe has their own folder in the root of the io.supertokens package. For example, this is the emailpassword recipe folder.

In the folder, we define everything (except for the APIs) that a recipe needs:

  • Exceptions
  • Enums
  • Constants
  • Functions (these are usually found in the file whose name matches the recipe ID). They are a set of functions that can be used to create the APIs that are exposed by this recipe. An example of this is EmailPassword.java.
  • Classes to hold information (like this one)

APIs for each recipe are defined in /webserver/api/ folder.

Recipes need to interact with some storage, and that is done via the StorageLayer abstraction.

Storage Layer#

There are two types of storages:

  • SQL
  • NO_SQL

Not all recipes support both, but all support SQL

The StorageLayer.java class exposes functions which return an instance of each type of recipe storage. For example, we have:

  • SessionStorage: Which is an interface designed for querying the dbs based on the APIs of the session recipe. These functions are used in the main session recipe logic in session/Session.java.
  • EmailPasswordStorage: This is an interface designed for querying the dbs based on the APIs of the emailpassword recipe..

Plugin interface#

This is a separate java project which defines interfaces that are used by the core to interact with various databases - like mysql, postgres, mongdb, sqlite.

It has a set of interfaces per recipe (used by the corresponding recipe in the core.):

  • An interface that is shared by sql and no sql dbs: Example
  • An interface that is to be implmented only by sql dbs: Contains functions that are required to be called in a db transaction. Example
  • An interface that is to be implmented only by no sql dbs. Example.

It has several classes to support the interface. For example, a function in an interface must return a User object. That class is defined alongside the interface in this project.

important
  • This project should not depend on any external library (outside of what's provided in the JRE), nor should it depend on the core or the db plugins.
  • Instead, the core and the db plugins depend on this project.
  • The core and db plugins should depend on just one plugin interface version at one time.

DB plugins#

These are separate java projects (one per database) that implement the plugin interface. An example of this is the MySQL plugin project.

They are responsible for creating and maintaining a connection pool to the underyling db, providing a way to implement transactions (if SQL), and to implement all the functions in the plugin interface.

There is also an in memory db in the core itself (using sqlite) here. The code structure of this is very similar to that of other plugins which are separate java projects.

Which frontend SDK do you use?
supertokens-web-js / mobile
supertokens-auth-react