Resource Based Authentication

User Accounts

One of the most unique concepts of Form.io is how Users are defined and utilized. While other platforms have distinct User entities, and are managed within their own API and Database namespaces; Form.io is different in that a User is actually a Submission within a Resource form. This enables any Resource to establish the structure of a User account and support multiple types of user models within your application. This becomes very useful if your data management application needs to keep track of multiple User models as well as manage the different ways in which users can be assigned access to other forms and submission data.

For example, if you were creating a Patient Onboarding application, several resources can be used to define the different user models that would be used, such as.

  • Patient - This would be a resource that would include fields that would define a clinic patient such as First Name, Last Name, Patient ID, etc.

  • Physician - This would be a resource that would include the fields that would define a clinic physician such as Specialty, Physician ID, etc.

  • Admin - This resource could be used to define any Clinic administrators that need to help the Physicians manage the patient records.

Since Users are simply Submissions within a form, they contain all the same elements as any other submission within any Form. The primary difference between a User submission and any other Submission within Form.io is that a User submission will almost always take advantage of a property on the Submission model called "roles". This property is used to define all of the Roles that a user has within a project and is defined in the following section. A typical user submission looks like the following.

{
    "_id": "5ffe1a78bf0654a91f191b2e",
    "data": {
        "email": "bob@example.com",
        "firstName": "Bob",
        "lastName": "Smith"
    },
    "owner": "5e5411ba1e29ee1aab5031d9",
    "roles": [
        "5e5411c11e29ee5fca5031e8",
        "5ffe1a2cbf06545768191b0a"
    ],
    "metadata": {
        "timezone": "America/Chicago",
        "offset": -360,
        "origin": "https://remote.form.io",
        "referrer": "",
        "browserName": "Netscape",
        "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.101 Safari/537.36",
        "pathName": "/",
        "onLine": true,
        "login": {
            "attempts": 0,
            "last": 1610488618123
        }
    },
    "form": "5e5411c11e29eef4885031ea",
    "project": "5e5411c11e29eeb3015031e6",
    "externalIds": [],
    "created": "2021-01-12T21:54:00.403Z",
    "modified": "2021-01-12T21:54:00.412Z"
}

Due to security constraints, roles within a user can ONLY be added through a Role Assignment action. It is not possible to update a submission to "add" roles to a submission via POST, PUT, or PATCH requests. They can, however, be removed from a submission via these API methods.

Session Management

The Form.io platform ensures that every authentication within the platform is associated with a current "session". A Session is a mechanism to connect authenticated requests made by the same JWT token, and also ensures that "sessions" can be invalidated once a login occurs. This works by adding a Session ID to a JWT Token ID to each token provided to a user. This can be seen by copying your JWT Token from your localStorage (usually found within the formioToken variable) into jwt.io, which will give you the following.

{
  "user": {
    "_id": "5e5411ba1e29ee1aab5031d9"
  },
  "iss": "https://api.form.io:3000",
  "sub": "5e5411ba1e29ee1aab5031d9",
  "jti": "5fffbb5646d76c292a7b5df1",
  "iat": 1610595158,
  "exp": 1610609558
}

The jti property is your current Session ID, and will change if you logout and re-login.

Once a user logs out of their account, by hitting the logout API, the current session will become invalid, and all outstanding JWT tokens that use that session ID will no longer be able to be used. The user must first login again, which will re-establish a new session, and then that JWT token can be utilized to make API calls into the Form.io platform.

The Session Management system is used as an added security measure to enforce that JWT tokens cannot be used again once a user has logged out of their account. This also protects the situation where if any user is using multiple devices and logs out of one device, their session will also be logged out of all other devices.

Login and Registration

Once a user resource has been established, a project can now be configured to allow a user to login or register within a project. This is accomplished by creating a Login form and Registration form respectively.

Creating a Login Form

A login form for a user is usually created by default within a project, but it is important to understand what it is there to accomplish and how to create your own for any other users you wish to have Login to a Form.io project. Any login form can be created by creating a new Form and building that form as you would like to display it within your application. For example, your login form may look like the following.

Now that you have a login form created, the next thing that needs to occur is that you will need to add a Login Action to the form. This can be done by navigating to the Actions, and then select Login action, and then select Add Action. Next, you will configure the Resources you would like to search when performing the Login account search. Considering that any Resource can be defined as a "user", this allows you to search multiple resources to perform a login through a single form. You will also want to map the fields within the form that are defined as the Username Field and the Password Field as follows.

Next, click Save to save this action.

Next, we will want to remove the default Save Submission action since for a Login process, it does not make much sense to "save" the submission being made to that form.

In some situations, you may actually want to keep the Save Submission action attached to the Login form. This is a good way to keep an audit log of everyone who has logged into your system.

Now that you have a Login action attached to the form, and the Save Submission action removed, the last thing that needs to be configured for a Login form is to allow Anonymous users the ability to submit the form (since users will be anonymous when this form is submitted). This can be configured within the Access section of your form, where you will add Anonymous to the Create Own permission as follows.

Now that we have our Login form configured, we can either embed the form within the application, or by submitting a POST request to the submission endpoint of this form API. For example, if this form endpoint is configured as "user/login", we can login using the following API.

POST: https://yourproject.form.io/user/login/submission

Creating a Registration Form

A Registration form is identical to a Login form with one difference, the Save Submission action. Within a Registration form, you will always want to Save the submission of the registration, which can be configured by adding this action to your form in the actions tab. Once you add a new Save Submission action, the next thing you will need to ensure is that you are saving the record to the correct resource for the registration process. This is done within the configuration of the Save Submission action, where you can select which resource you would like to save the submission to, and then perform a field map so that the correct fields from the registration are passed along to the underlying resource as shown below.

Assuming that your registration form has the URL path of "user/register", you can now embed this within your application, or you can register a new user into your project using the following API command.

POST: https://yourproject.form.io/user/register/submission

Last updated