Example framework for XData with Sphinx authentication and authorization

As it was quite a steep learning curve for me to implement an XData server with authentication and authorization through a Sphinx server with asymmetric encryption, I decided to build a simple reference framework. To facilitate requesting support (with example code), it was built with only Delphi standard components and TMS Biz (including TMS Logging). Initially it was intended for my own use but I decided to document it for future reference and share on this forum so that it may be of use to anyone else who needs to get started and experiences the same start up challenges as I did.

The framework is available for download from GitHub on:

I have also written a guideline document (PDF) with details on how to use this framework and what to look out for:

XData-Sphinx Framework.pdf (119.8 KB)

The framework includes the following:

  • XData and Sphinx servers implemented as Windows services.
  • A Sphinx Manager desktop application to configure the Sphinx server and manage users. Users are intended to be managed from the "back office" only (i.e. no self-registration).
  • An XData Client application to test the framework (VCL Client) and demonstrate the implemented access rights.

It must be noted that all code for email functionality (account details and confirmation tokens) has been commented out. The user of the framework is expected to implement his/her own functionality.

By no means is the framework complete. There's certainly room for improvements and additions. I already have 3 issues that are on the to-do list (ref. section 2 in guideline document):

  • Fix the issue with the SparkleHttpSysDispatcher.OnStart event in the Sphinx server (see comments in code)
  • Identify where (and how) to best implement logging of user logins, in Sphinx (token issued
    to whom and when) and XData (who logged in and when).
  • Find a good way to handle access token life time (now set to 3600 seconds or 1 hour) and
    expiry. Now the user may be inactive for some time and when resuming work, the token
    may have expired and pending edits cannot be saved (401 – token expired).

All comments and suggestions are welcome. Please add them to this topic so that anyone can view them and provide comments or suggestions.

Finally: thanks to Wagner Landgraf for all the patient support and explanations.

1 Like

@van_den_Berg_Mark Impressive! Many thanks for your contribution and I believe other users will also appreciate it.

1 Like

One thing I forgot to ask. In the VCL Client I log/show the user info (SphinxLoginUserLoggedIn > LogUserInfo):

  if Info.Profile <> nil then
  begin
    TMSLogger.Info('User ID: ' + Info.Profile.Subject);

    TMSLogger.Info('User name: ' + Info.Profile.PreferredUserName); // Always empty?

    TMSLogger.Info('Email: ' + Info.Profile.Email);
    TMSLogger.Info('EmailVerified: ' + Info.Profile.EmailVerified.ToString(TUseBoolStrs.True));
  end
  else
    TMSLogger.Info('No user profile.');

For some reason PreferredUserName comes up as an empty string. Of course I can easily add a claim 'user' to the JWT token in the Sphinx server like:

procedure TmodServerContainer.SphinxConfigConfigureToken(Sender: TObject; Args: TConfigureTokenArgs);
begin
   ....
  Args.Token.Claims.AddOrSet('user', TSphinxUserEx(Args.User).UserName.Value);
  Args.Token.Claims.AddOrSet('scope', TSphinxUserEx(Args.User).Access_Level);
   ......

I always like to show a status, including 'logged in as ...' (not just email), so how (and where best) can I retrieve the user name from the claim in the access token (JWT) in the VCL Client after the user logged in? Or is there another/better way to get the UserName?

What you are doing is fine and a valid way.

Thanks, but how do I extract the 'user' claim (and its value) on the VCL Client side? All I have is the IAuthResult (Info) and I don't see how to extract it from there...

You can use this:

UserName := Info.Profile.Source['user'].AsString;

But if instead user you set the preferred_username claim, then you can read it directly from Info.Profile.PreferredUserName.

1 Like

Hi Mark,

Yay, all is working. Now to get the email authorization to function.

Not sure if you can answer the question: Instead of using the SQLite database as per the example, is it possible to use the main application's data base (MSSQL) to store the user details and access to the system. So, instead of the .db it connects to an MSSQL database with the same table names and Field names? This maybe a question for Wagner?

Regards
Tom Dalton

1 Like

Yes, of course, TMS Sphinx uses TMS Aurelius under the hood as the database layer, so all TMS Aurelius supported databases are also supported by TMS Sphinx.

In the specific case of Mark's example, you have Module.Sphinx.Server.pas file which is data module containing the Sphinx Server and the database connection represented by the acSphinx component which is a TAureliusConnection.

Just change the TAureliusConnection settings properly to point to another database/component set, as explained here:

1 Like

Hi Wagner,

Sorry I did not see this post; so, I asked the same question again. Apologies. Please ignore.

Regards
Tom Dalton