What is hosted form
Hosted form is a customized HTML page of Identify Runtime to allow a user to edit HTML, binding, CSS and JavaScript of that page using REST API or Safewhere Admin. Its content is stored in the SharedConfigurationSettings table. Because of the possible security issues, the hardest part of offering hosted forms is to offer customizations while still making sure that user cannot manipulate any other data from unauthorized access (read, write, delete). The hosted form syntax is dotliquid.
Full list of supported hosted forms
# | Form name | Original Razor file |
1 | Login | AuthenticationList.cshtml |
2 | Reset Password | ForgotPasswordPage.cshtml |
3 | My Profile | This is a custom css for my profile page |
4 | Simple Login | UserNamePasswordAuthentication.cshtml |
5 | Error | Error.cshtml |
6 | Report Error | ReportError.cshtml |
7 | Change Password | ChangePassword.cshtml |
8 | Change Password Result | ChangePasswordResult.cshtml |
9 | Renew Password Page | RenewPasswordPage.cshtml |
10 | Renew Password email sent success | RenewPasswordEmailSentSuccess.cshtml |
11 | Renew Password Successfully | RenewPasswordSuccessfully.cshtml |
12 | Renew Password Unsuccessfully | RenewPasswordUnsuccessfully.cshtml |
13 | OTP Malformed Request Error | OtpMalformedRequestError.cshtml |
14 | Enable Authenticator | EnableAuthenticator.cshtml |
15 | Login With Authenticator | LoginWithAuthenticator.cshtml |
16 | OTP Authentication | OtpAuthentication.cshtml |
17 | OTP Authentication Failed | OtpAuthenticationFailed.cshtml |
18 | OS2faktor Device Registration | OS2faktorDeviceRegistration.cshtml |
19 | OS2faktor No Device | OS2faktorNoDevice.cshtml |
20 | OS2faktor User Rejected | OS2faktorUserRejected.cshtml |
21 | OS2faktor Error | OS2faktorError.cshtml |
22 | OS2faktor Pick Device | OS2faktorPickDevice.cshtml |
23 | OS2faktor Login | OS2faktorLogin.cshtml |
24 | Onboarding succeeded | OnboardingSucceeded.cshtml |
25 | Recovery code | RecoveryCode.cshtml |
26 | Enable WebAuthn | EnableWebAuthn.cshtml |
27 | Login With WebAuthn | LoginWithWebAuthn.cshtml |
28 | WebAuthn Error | WebAuthnError.cshtml |
29 | OTP Authentication Server Error | OtpAuthenticationServerError.cshtml |
30 | Enable Device Authentication | EnableDeviceAuthentication.cshtml |
31 | Policy Script Error | PolicyScriptError.cshtml |
32 | Generic Error | GenericError.cshtml |
33 | Restart login | RestartLogin.cshtml |
34 | HRD No Identity Provider Determined | HRDNoIdentityProviderDetermined.cshtml |
35 | First factor web authentication login | FirstFactorLoginWithWebAuthn.cshtml |
36 | First factor input user name | FirstFactorUsername.cshtml |
37 | First factor web authentication login error | FirstFactorWebAuthnError.cshtml |
38 | Delete Coookies | DeleteCookies.cshtml |
Hosted form layout
Customers typically want to maintain a consistent look and feel across all the hosted forms of an Identify tenant. For hosted form, we also provide a Liquid site layout which is similar to that of Razor views. The layout is a specific shared configuration name "CustomContent|SiteLayout":
Layout elements
Element in layout is a block of content to render the content from a specific view. Currently, hosted form layout supports the list of elements below:
- Title header
{% block "titleheader" %} {{Resources.OtpResources.OtpAuthenticationView_TitleHeader}} {% endblock %}
- Title content
{% block "titlecontent" %} {{Resources.OtpResources.OtpAuthenticationView_TitleContent}} {% endblock %}
- Link to login selector
{% block "linktologinselector" %} //Html content here {% endblock %}
- Sidebar
{% block "sidebar" %} //Sidebar content {% endblock %}
- InitScript
{% block "initscript" %} //Custom initialized javascript code {% endblock %}
- Content
{% block "content" %} //Main form content {% endblock %}
Using the layout for a specific form is as simple as using the "extends" syntax to inherit the layout:
Common fields
- Captchar image
{{ Captchar }}
- Anti-Forgery Token hidden
{{ Csrf }}
- Copyright info
{{Copyright}}
Text Resource support
All text resources from Identify runtime (and all plugins) can be used from the hosted form the same way as how we are doing for Razor views:
New View Engine for Hosted form
Behind the scene, we implemented a new view engine for Liquid views which looks up for views from database. The view engine has the following components:
- IFileSystem: Implement the interface to get the liquid template.
- IViewEngine: Implement the engine to render html from liquid template.
- IView: Prepare data model, text resources, other required data and render the view using DotLiquid
How to add a custom Liquid HTML view to hosted form
You can add a new hosted form in 4 steps:
Step 1: Locate the Cshtml view file in Identify Runtime
Step 2: Transform model object of that cshtml page to a plain object. If the transformed model is too complex or has too many dependencies, we must simplify it to only contain necessary data. This can be done by implementing a type converter for the target model.
For an example, the original AuthenticationList.cshtml razor view is:
And the model is:
Usually Razor view has code that manipulates the model object to compute data that is needed by a view. Since you can’t execute C# code in a Liquid view, you need to pre-compute those data in C# code to a dedicated model object for Liquid view. The computed Liquid model is an anonymous object. In order to do that, you can use TypeConverter:
The new anonymous object contains everything needed to render a full page of AuthenticationList.
Step 3: The hosted form is a HTML page with liquid syntax containing all required layout elements to render the page. No partial rendering is supported.
The Liquid view engine will look up for the custom Liquid viewfrom the SharedConfigurationSettings table by using the key "CustomContent|SignOnAuthenticationList" and render it. The transformed model at step 2 is passed to the liquid view as a Model object.
Step 4: Now you can try to run and test 2 cases: hosted form is active and hosted form does not exist or is inactive.
How to apply a custom hosted using Identify Admin (/admin)
Case study: you want to create a custom AuthenticationList view for each protocol connection (hosted forms currently only supports the view that is used for all protocol connections by default). After you have created a custom Liquid view, you can apply it by doing the following steps:
- Access the Identify Admin site.
- Access the System Setup > Field Configurator, and choose to add a new Field Configuration
- Name: input the name with the syntax: CustomContent|{viewname}, e.g. CustomContent|AuthenticationList
- Expression: enterLiquid view content
- Resource key: set it to "Html" and save the field configuration.
- Open the SAML2.0 / OAuth2.0/OpenID Connect application, you will see the new AuthenticationList view that you made above replaced for the original AuthenticationList view.
How to apply a custom hosted using Safewhere Admin
- Access the Safewhere Admin site.
- Access the Settings\Field Configurator, and choose to add a new Field Configuration
- Name: input the name with the syntax: CustomContent|{viewname}, e.g CustomContent|myapplication1
- Expression: enter Liquid view content
- Resource key: set it to "Html" . Then save the field configuration.
- Access the Settings\System, verify the setting: Show Home Realm Discovery configuration is True
- Access the Application list, open the SAML2.0 / OAuth2.0/OpenID Connect application.
- Access its Home Realm Discovery tab, enter the view name to the "Authentication list view name" setting, e.g inthis sample, it is "myapplication1"
Breaking changes
To support liquid template, we must get rid of using "ViewBag" from MVC controller that causes a breaking change on "RenewPasswordPage". The ViewData object is used instead.
So, the Razor view should be updated to adapt to the change: