Multi-Tenancy, Authorisation, Authentication

Last updated: October 6, 2025

The Factor platform is based on a multi-tenancy, software-as-a-service (SaaS) architecture. In this article we discuss the base mechanisms for segregating data, for authentication of tenant clients and the general authorisation mechanism.

Multi-Tenancy

The Factor Platform is, by its nature, multi-tenanted. All subjects (users, machines) are bound to a tenant. Even internal Factor services/staff are bound to itself as a tenant. The tenancy binding is typically performed during tenant and user onboarding. The result of the binding is that all tokens generated by the Factor Identity Provider (IDP) contains a tenant claim. This can not be tampered with due to the cryptographic mechanisms provided by JSON Web Tokens (JWTs).

All tenant data is, for the most part, logically, rather than physically, segregated. That is, all data is marked with a tenant binding. The data (resource) tenancy binding is one of the attributes used in the attribute-based access control system.

Tenant data is also encrypted both in transit and at rest.

Authentication

We use AWS Cognito as a base identity provider service (IDP). This means that all requests requiring authentication are mediated by Cognito. Before going further, let's get a few terms sorted.

A subject is an entity which is making a request to a secured system service. The following types of subjects are supported by the platform:

  • Customer person subject.

  • Factor person subject.

  • The Factor Single Page App (SPA).

  • Factor Service.

  • Customer App.

  • A script or CLI tool which uses Factor APIs; either customer or Factor.

Each subject type must be authenticated with the IDP before making a request. We use OAuth2 and OpenIdConnect (OIDC) protocols to authenticate each subject type; even our internal services are required to be authenticated to communicate with each other.

System or API Authentication

A system subject (such as a CLI or a Customer backend application) must obtain a JWT from the IDP before calling a Factor API. Typically, the grant type will be the OAuth Client-Credentials-Grant.

User Authentication

User authentication also uses OAuth. However, the flow is slightly different depending on the subject security realm and the method of interacting with the Factor services. Typically, the flow inherits from the OAuth authorisation-code-grant flow. Taking the Factor SPA as an example, the SPA uses the Factor IDP to manage user session state. When a user lands for the first time, the SPA uses the OAuth flow to log the user in. the Factor IDP then has a couple of techniques to perform the login. For our customers, this will typically be a federated authentication. Using a protocol such as SAML, the Factor IDP redirects the user to their home IDP, which performs the login and redirects back to the Factor IDP with authorised claims. The Factor IDP then creates a proxy subject binding itself back to the customer's IDP subject, and generates an ID-Token. The SPA uses this IDP token on API requests to Factor services.

Authorisation

The Authorisation framework is based on the general ideas of attribute-based access control, as defined in the NIST ABAC paper. That is, authorisation is based on what attributes the subject has, rather than the roles they are in.

Furthermore, the authorisation platform is based on a concept known as Fine-grained access control (FGA). We use a formal policy language to state specific allow and deny rules based on the subject's attributes. This approach allows for fine-grained control over authorisation decisions.

In essence, an authorisation request asks the question “Can this principal take this action on this resource in this context?”. More formally, this is known as PARC authorisation.

  • P is the principal,

  • A is the action,

  • R is the resource, and

  • C is the request context.

The Factor Policy Decision Point (in NIST terms) is a Cedar-based rules system for both policy language definition as well as the making runtime policy decisions. Cedar allows the testing of any number of fine-grained rules during a policy decision request. As a very basic example, consider the following rules which may be defined using the Cedar policy language.

  1. Factor subjects can only perform actions on Factor resources.

  2. Tenant subjects can only perform actions on any resource "owned" by their tenant.

  3. Tenant subjects may only perform actions which align with the level of their subscribed plan.

The 2nd and 3rd rules might look like this in Cedar.

// Allow any principal to request initiate a forecast as long as the principal
// has the product feature that the command resource scope.
permit (
  principal,
  action in [Factor::Action::"initiateForecast"],
  resource
)
when
{
  principal.hasTenant
    .hasSubscribedPlan
    .atOfferedPlanTier >= resource.isAtPlanTier
};

We use the AWS Verified Permissions (AVP) service to manage both the policy information and the policy decision making. Each service request requiring authorisation makes a call to AVP, stating the context in which it is being executed and the attributes of the subject (the principal's tenant, the plans, the resource's tenant, etc). AVP provides an allow/deny back to the service, and the service is then responsible for executing policy enforcement. A typical deny response would be a HTTP 401 UnAuthorised.