User Authentication

From SocialStack

User authentication is the process of users providing some sort of information and in return getting a token (usually stored as a cookie) which can then be used automatically on multiple requests. The flow is not specific to passwords and is also highly pluggable, with the ability to add multiple authentication requirements like two factor authentication (install Api/TwoFactorGoogleAuth) on the same user request, or use more advanced authentication mechanisms like SSO.

How authentication works

  • First a request is sent to /v1/user/login. The JSON payload is mapped to a Api.Users.UserLogin object which is a partial class (extensible), meaning you can add custom fields to it if you need them.
  • Next, the UserLogin object is passed to an event handler called Events.UserOnAuthenticate
  • Multiple authentication providers can listen to this event. They can also work together, such as requiring both a password and a 2FA code. An authentication provider should attempt to identify the user account that it is authenticating, and then attempt to authenticate.
  • If you're creating an authentication module which is intended to be used on multiple projects, it's suggested to make sure that your module checks if some previous provider has already authenticated a user. Do this by checking if there is a LoginResult currently, and if there is, return it.
  • Two factor modules however require a LoginResult to exist. I.e. A previous authentication provider successfully authenticated, and now your secondary one must authenticate as well using other details from the UserLogin object. To signal that a successful authentication happened and that 2FA is required but the secondary auth has not passed yet, set MoreDetailRequired on the LoginResult object. This object is simply a canvas structured object, meaning it can indicate a UI component to display. See the Api/TwoFactorGoogleAuth module for an example of that.
  • Projects default to having the password authentication module installed. You can uninstall it if you want, but its job is to provide username or email and password authentication behaviour. It's Api/PasswordAuth.
  • The PasswordAuth module selects a user to authenticate by checking if PasswordAuthService.OnSelectUser exists. This is a simple event method which you can set in order to change the actual query which runs when choosing a user to authenticate. Typically this event handler is set from within a small service such that it can have easy access to the UserService:
using Api.Users;
using Api.Eventing;
using Api.Contexts;
using Api.PasswordAuth;

namespace Api.CustomUserQuery;


public partial class CustomUserQueryService : AutoService
{

    public CustomUserQueryService(PasswordAuthService passwordAuth)
    {
         passwordAuth.OnSelectUser = async (Context context, UserLogin loginDetails) => {
            // Use any query you'd like along with custom fields in loginDetails to select the user account you would
            // like to use. Note that this does not handle authentication - only account identification.
            return await users.Where("Email=?", DataOptions.IgnorePermissions).Bind(loginDetails.Email).First(context);
         };
    }

}