Protected
Introduction
Protected pages can only be accessed with a logged in app user. App users are special app specific users that can
be set up to access specific applications.
Login and registration is up to the specific applications. Either it allows user registration from a public page
or user creation is handled in some admin panel instead.
Note that app users cannot exist without an application, and the users cannot access or log in if they are not associated
with an existing application (as opposed to erply account users). These user sessions cannot access erply back-office
applications and regular pages.
Public routes always are prefixed with either public/ or b2b/ (except on custom domains).
Setup
Set the page to allow b2b access to set this protection level.
This can be configured in the template editor mode under the ‘Publish setting’ right menu.
Note
It is also possible to set an optional expiration date to the page (UTC unix value) after this
timestamp has passed on the server the will no longer be accessible using the b2b endpoint.
Use authentication config input set the value.
Also note that this setting is based on applications or auth domains.

Each user requires the application domain to be able to create a valid session for the application. By default,
the application domain is the applications uuid. You can use the ‘Authentication domain’ field to set a custom value -
if the same value is set for multiple applications then the applications can share the users.
Use the ‘Redirect non-authenticated B2B users to page’ option to automatically redirect to login or error
page invalid accesses.
User creation/registration
Users can either be created using a public registration form (for stores, b2b pages etc), or creation is managed internally
within another page or application.
Manual app user creation
Here the creation and management of users would be handled by a protected page (either erply session or a different set of app users).
Use the automat api endpoints to create the users and manage them.
https://template-engine-eu10.erply.com/api/documentation/index.html#/app-user
Domains
Domains under the user determine what application pages the user can access.
Auth drivers
Auth drivers indicate what authentication methods the user is allowed to use to log in.
Inbuilt methods: password, pin and openid
Open id
Open ID setup can be used to create custom sso methods for login. Each provider that is set up for the login page
can then be used with the users to log in.
Creating a custom open id driver:
- In the login page template, navigate to the Publish settings -> OpenID Configuration tab.
- Use the ‘Add new configuration’ button to register a new open id provided (driver). Fill in the required fields and
fields related to the provider. Note that the ‘Provider’ field will be used as the driver name.
The ’email’ scope is also required as app users will be matched with the email.
- In the login command set the auth driver to the created one.
- In order for the users to be able to use it they would need to have the ‘ms_entra’ auth driver. Note that for open id
auth drivers the value field will not be used.
- The jwksUrl endpoint needs to point to the public keys configuration.
This example assumes the open id configuration was given the provider name of ‘ms_entra’.
<form method="post">
<input type="hidden" name="AutomatApi.B2BLoginInput.Redirect" value="b2b-2-members-page">
<input type="hidden" name="AutomatApi.B2BLoginInput.AuthDriver" value="ms_entra">
<button type="submit">
Microsoft SSO
</button>
</form>
There is no limit to the open id providers. You can set up multiple providers to the same auth provider as-well (multiple app’s in ms entra for example).
Public registration page
With this you can create public facing endpoint where users can be created by customers themselves.
Domains
With inbuilt forms the domain is always taken from the registration template.
Auth drivers
With inbuilt from the auth driver used is always ‘password’
Setting up public registration page
Create a public page that implements the automat api’s registration form.
Use the Session.Customer.ID to detect if the user is already logged in.
Optionally, the AutomatApi.B2BLoginRegisterInput.LoginOnSuccess
can be used to automatically login
newly created user and AutomatApi.B2BLoginRegisterInput.Redirect
to redirect the user to a specific
page after successful login.
Check the automat api B2BLoginRegisterInput data source docs for additional available fields.
<!-- Read registration errors -->
<div class="my-error-container">
{{ range .Data.Errors }}
<span class="my-error-message">{{ . }}</span>
{{ end }}
</div>
{{ if .Session.Customer.ID }}
<h1>Already registered</h1>
{{ else }}
<h1>Register a new user</h1>
<form method="post">
<input type="hidden" name="postActionEntity" value="B2BLoginRegisterInput">
<input type="hidden" name="postActionRedirect" value="b2b-login-demo-page">
<!-- Configure autologin and redirect -->
<input type="hidden" name="AutomatApi.B2BLoginRegisterInput.LoginOnSuccess" value="1">
<input type="hidden" name="AutomatApi.B2BLoginRegisterInput.Redirect" value="b2b-2-members-page">
<br>
<label for="firstName">First name</label>
<input type="text" id="firstName" name="AutomatApi.B2BLoginRegisterInput.Firstname">
<br>
<label for="lastName">Last name</label>
<input type="text" id="lastName" name="AutomatApi.B2BLoginRegisterInput.Lastname">
<br>
<label for="email">Email</label>
<input type="text" id="email" name="AutomatApi.B2BLoginRegisterInput.Username">
<br>
<label for="password">Password</label>
<input type="password" id="password" name="AutomatApi.B2BLoginRegisterInput.Password">
<br>
<button type="submit">Register</button>
</form>
{{ end }}
Setting up public login page
Create a public page that implements the automat api’s login form.
Use the Session.Customer.ID to detect if the user is already logged in.
Optionally the AutomatApi.B2BLoginInput.Redirect can be used to redirect the user
to a specific page after successful login
<!-- Read login errors -->
<div class="my-error-container">
{{ range .Data.Errors }}
<span class="my-error-message">{{ . }}</span>
{{ end }}
</div>
{{ if .Session.Customer.ID }}
<p>Welcome {{ .Session.Customer.FirstName }}</p>
{{ else }}
<form method="post">
<label for="username">Email</label>
<input type="text" id="username" name="AutomatApi.B2BLoginInput.Username"/>
<br>
<label for="password">Password</label>
<input type="password" id="password" name="AutomatApi.B2BLoginInput.Password"/>
<br>
<button type="submit">Login</button>
</form>
{{ end }}
Using dynamics
Starting from version 1.246.0, GoErp allows to use dynamic api features while creating register,
login and others b2b authentication calls. This allows to create multiple requests and chain data
between them, including authorization calls.
Note
Those API calls works properly only inside GoErp templates, because b2b (public) authentication
depends on the template configuration, therefore all b2b API endpoints requires b2bKey
to be
sent in the request header. This key is available inside session and could be chained to the
API request header.
More about b2b API calls read in
the Automat API documentation.
Registration page
A simple registration page using API and dynamics. All page configuration steps remains same as for
model based b2b authentication.
<h1>Register page</h1>
<form method="post">
<input type="hidden" name="AutomatApi.Api.Post.register" value="v1/b2b/register-user">
<!-- Use chaining to pass b2b key to the header -->
<input type="hidden" name="AutomatApi.Api.Header.register.<-b2bKey" value="Session.key">
<!-- Use .Tools.B2bAuthDomain to get the domain -->
<input type="hidden" name="AutomatApi.Api.Json.register.string.domain" value="{{ .Tools.B2bAuthDomain }}">
<!-- Setup redirect on succeed, if needed. It will be triggered only if all calls in this
template are successful. So, if registration fails, we stay on this page, very useful. -->
<input type="hidden" name="Form.Redirect" value="10-b2b-in-page">
<fieldset>
<label for="firstname">Firstname:</label>
<input id="firstname" name="AutomatApi.Api.Json.register.string.firstname" value="">
<label for="lastname">Lastname:</label>
<input id="lastname" name="AutomatApi.Api.Json.register.string.lastname" value="">
</fieldset>
<fieldset>
<label for="username">Username:</label>
<input id="username" name="AutomatApi.Api.Json.register.string.username" value="">
<label for="password">Password:</label>
<input id="password" name="AutomatApi.Api.Json.register.string.password" value="">
</fieldset>
<!-- Login would be performed automatically only if this parameter set to 1 -->
<input type="hidden" name="AutomatApi.Api.Json.register.string.triggerLoginAfterRegister" value="1">
<button type="submit">Register</button>
</form>
Note
Please note that if the triggerLoginAfterRegister
parameter is not passed or set to 0
, the user
will be registered but not logged in. Although, Form.Redirect
will be triggered anyway and try to
access the protected area (10-b2b-in-page
in this case). Therefore, while user not logged in, the
10-b2b-in-page
page configuration will redirect to the login page (if configured). So, this could
be confusing.
Login page
Here we will just use the username and password, and redirect to the protected area when successful.
<h1>Login page</h1>
<form method="post">
<input type="hidden" name="AutomatApi.Api.Post.login" value="v1/b2b/login">
<!-- Use chaining to pass b2b key to the header -->
<input type="hidden" name="AutomatApi.Api.Header.login.<-b2bKey" value="Session.key">
<!-- Use .Tools.B2bAuthDomain to get the domain -->
<input type="hidden" name="AutomatApi.Api.Json.login.string.domain" value="{{ .Tools.B2bAuthDomain }}">
<!-- Setup redirect on succeed, if needed. It will be triggered only if all calls in this
template are successful. So, if login fails, we stay on this page, very useful. -->
<input type="hidden" name="Form.Redirect" value="10-b2b-in-page">
<fieldset>
<label for="username">Username:</label>
<input id="username" name="AutomatApi.Api.Json.login.string.username" value="">
<label for="password">Password:</label>
<input id="password" name="AutomatApi.Api.Json.login.string.password" value="">
</fieldset>
<button type="submit">Login</button>
</form>
Samples
In the following sample we have a registration, login and a members area. This shows how we restrict the members area
to only read results for the logged in customer.
Page setup
Note
The public features only work if the registration, login and any members pages belong to the same application or auth
domain.
Registration page
A simple registration page with minimal inputs.
<!DOCTYPE html>
<html>
<body>
<h2>Register a new user</h2>
<form method="post">
<input type="hidden" name="postActionEntity" value="B2BLoginRegisterInput">
<input type="hidden" name="postActionRedirect" value="b2b-2-login-page">
<div class="user-box">
<input type="text" name="AutomatApi.B2BLoginRegisterInput.Firstname" required="">
<label>Firstname</label>
</div>
<div class="user-box">
<input type="text" name="AutomatApi.B2BLoginRegisterInput.Lastname" required="">
<label>Lastname</label>
</div>
<div class="user-box">
<input type="text" name="AutomatApi.B2BLoginRegisterInput.Username" required="">
<label>Email</label>
</div>
<div class="user-box">
<input type="password" name="AutomatApi.B2BLoginRegisterInput.Password" required="">
<label>Password</label>
</div>
<!-- Read possible registration errors -->
<div>
{{ range .Data.Errors }}
<span>{{ . }}</span>
{{ end }}
</div>
<button type="submit">Register</button>
</form>
</body>
</html>
For publish settings we enable the ‘Allow B2B and public access’ checkbox
Also since registration allows more fields to be used we also need to fill in the parameter whitelist of
the value we will allow to be used, in this case we will fill the ones we have defined in the form.

Login page
Here we will just use the username and password, and redirect to the members area when successful.
<!DOCTYPE html>
<html>
<body>
{{ if .Session.Customer.ID }}
<h2>Already logged on!</h2>
{{ else }}
<h2>Login</h2>
<form method="post">
<input type="hidden" name="AutomatApi.B2BLoginInput.Redirect" value="b2b-2-members-page">
<div class="user-box">
<input type="text" name="AutomatApi.B2BLoginInput.Username" required="">
<label>Username</label>
</div>
<div class="user-box">
<input type="password" name="AutomatApi.B2BLoginInput.Password" required="">
<label>Password</label>
</div>
<div class="my-error-container">
{{ range .Data.Errors }}
<span class="my-error-message">{{ . }}</span>
{{ end }}
</div>
<button type="submit">Login</button>
</form>
{{ end }}
</body>
</html>
For publish settings we enable the ‘Allow B2B and public access’ checkbox.
Login model parameters are automatically whitelisted, so we should not need to fill them here.
Members page
On the members page we will generate a simple list of documents for the currently logged on member.
We use the preset to read session id to the request and prevent it from being adjusted via any parameters.
<!DOCTYPE html>
<html>
<body>
<h1>Members page</h1>
<form method="post">
<input type="hidden" name="AutomatApi.B2BLogoutInput.Logout" value="1">
<button type="submit">Logout</button>
</form>
<h2>Welcome {{ .Session.Customer.FirstName }} to the members area</h2>
<!-- Erply api response data in the 'records' field -->
<h2>My orders</h2>
<form method="POST">
<!-- Request definition -->
<input type="hidden" name="ErplyApi.Api.Post.getDocs" value="getSalesDocuments" data-preset-val="getSalesDocuments">
<button type="submit">Reload orders</button>
</form>
<ul>
{{ $salesDocs := (.Data.ErplyApi.Api.Requests.getDocs.Response.Get "records").Array }}
{{ if $salesDocs }}
{{ range $salesDocs }}
<li>{{ .Get "id" }} / {{ .Get "type" }} / {{ .Get "clientName" }}</li>
{{ end }}
{{ else }}
<li>You currently have no orders!</li>
{{ end }}
</ul>
</body>
</html>
Note
By default all public access groups do not have access to read documents. This right needs to be given under the public
user groups (starting with ‘app_public’ and ‘app_b2b’) by the account administrator in the backoffice.
Every application or authentication domain will have a separate user group with rights assigned to them.
For publish settings we enable the ‘Allow B2B access’ checkbox as we will only want logged in members to access it.
We also set the redirection to the name of the login page, so whenever its being accessed without a proper session
it will be automatically redirected.

We are also using dynamic api here, so we will add the ErplyApi.Api.Post.getDocs -> getSalesDocuments to the request
whitelist.
Under URl configuration we add the preset ErplyApi.Api.PostParam.getDocs.<-clientID : Session.customer.ID
This will write the current session customer id to the request when it is being done, since we do not allow the parameter
to be adjusted in the parameters list then it cannot be changed to anything else.

Workflow
To test it:
- Register a new user
- Login with the created customer
- The members area only displays the members sales documents (use backoffice to create them or create a new page
that creates the documents for the member using the same method)