Handling User Sessions
This guide covers different aspects of system security and contains all information you need to handle user sessions of Structr applications. User registration with double opt-in, user password reset, authentication via direct login, authentication via JWT and provider-based authentication (OAuth). To make your Structr application as secure as it can be, the following links will provide more information:
User self-registration
Instead of creating users in the Structr backend manually in the Users and Groups section of Structr’s admin UI, you can allow users to sign-up/self-register. The registration process uses double-opt in by default. All you need is a simple page where new users can enter their e-mail address so Structr can send them an e-mail with a confirmation link.
The following pre-defined MailTemplate keys can be used to configure the self-registration process. In version 4.0 they have been renamed to have a more uniform structure.
Note: The Mail Configuration Settings have to be done for self-registration mails to be sent.
Name | Old Name (removed as of v4.1) | Used as | Default |
---|---|---|---|
CONFIRM_REGISTRATION_SENDER_ADDRESS | SENDER_ADDRESS | The sender address of the registration mail | structr-mail-daemon@localhost |
CONFIRM_REGISTRATION_SENDER_NAME | SENDER_NAME | The sender name of the registration mail | Structr Mail Daemon |
CONFIRM_REGISTRATION_SUBJECT | SUBJECT | The subject of the registration mail | Welcome to Structr, please finalize registration |
CONFIRM_REGISTRATION_TEXT_BODY | TEXT_BODY | The plaintext body of the registration mail | Go to ${link} to finalize registration. |
CONFIRM_REGISTRATION_HTML_BODY | HTML_BODY | The HTML body of the registration mail | <div>Click <a href='${link}'>here</a> to finalize registration.</div> |
CONFIRM_REGISTRATION_BASE_URL | BASE_URL | Used to build the link variable | ${base_url} |
CONFIRM_REGISTRATION_TARGET_PAGE | TARGET_PAGE | the target parameter value for the redirection target page name | register_thanks |
CONFIRM_REGISTRATION_ERROR_PAGE | ERROR_PAGE | the error parameter value for the error redirection target page name | register_error |
Notes:
- The visibility flags of these MailTemplates are ignored because the self-registration mail is created as a privileged user.
- A special
link
variable is provided for theTEXT_BODY
andHTML_BODY
templates and can be output with the usual syntax:${link}
- Example
link
:https://support.structr.com/confirm_registration?key=<CONFIRM_KEY>&target=/dashboard&onerror=/register-error
- Example
- From v4.1 scripting is enabled in two templates:
CONFIRM_REGISTRATION_TEXT_BODY
andCONFIRM_REGISTRATION_TEXT_BODY
. The script is being run in the context of the user (me keyword points to the user). - In any version prior to 4.1 scripting can not be used and simple text replacement is done
Registration Resource
The self-registration should be done via the registration resource. It is available under /structr/rest/registration
.
An un-authenticated user can issue a HTTP POST to that resource to begin the registration process. The accepted input attributes are configured in the configuration registration.customuserattributes
. eMail
is always supported and often used as a single attribute for registration.
The registration is then started by the user by making a HTTP POST request (via a signup form) to /structr/rest/registration
with the following body:
fetch("http://localhost:8082/structr/rest/registration", {
method: "POST",
body: JSON.stringify({
eMail: "user.name@mail.com"
})
})
The self-registration process would then send a mail using the above templates.
Notes:
- A resource access grant must be configured for public users to allow the POST method to the grant with signature
_registration
- jsonrestservlet.user.autocreate must be enabled in structr.conf to enable automatically creating users
Password Reset
To allow users to regain access to their account when they forgot their password we need to enable them to reset their password.
Note: The Mail Configuration has to be done for password retrieval mails to be sent.
Name | Used as | Default |
---|---|---|
RESET_PASSWORD_SENDER_ADDRESS | Sender address | structr-mail-daemon@localhost |
RESET_PASSWORD_SENDER_NAME | Sender name | Structr Mail Daemon |
RESET_PASSWORD_SUBJECT | Subject line | Request to reset your Structr password |
RESET_PASSWORD_TEXT_BODY | Plaintext mail body | Go to ${link} to reset your password. |
RESET_PASSWORD_HTML_BODY | HTML mail body | <div>Click <a href='${link}'>here</a> to reset your password.</div> |
RESET_PASSWORD_BASE_URL | Used to build the link variable | ${base_url} |
RESET_PASSWORD_TARGET_PAGE | target parameter value in the link variable. Specifies the redirect page after successful login. | /reset-password |
Notes:
- The visibility flags of these MailTemplates are ignored because the self-registration mail is created as a privileged user.
- A special
link
variable is provided for theTEXT_BODY
andHTML_BODY
templates and can be output with the usual syntax:${link}
- Example
link
:https://support.structr.com/reset-password?key=<PASSWORD-RESET-KEY>&target=/reset-password
- Example
- From v4.1 scripting is two templates:
RESET_PASSWORD_TEXT_BODY
andRESET_PASSWORD_HTML_BODY
. The script is being run in the context of the user (me keyword points to the user). - In any version prior to 4.1 scripting can not be used and simple text replacement is done.
Password Reset Resource
The reset password process should be done via the reset password resource. It is available under /structr/rest/reset-password
.
An un-authenticated user can issue a HTTP POST to that resource to begin the registration process. The accepted input attributes are configured in the configuration registration.customuserattributes
. eMail
is always supported and often used as a single attribute for registration.
The reset password process is then started by the user by making a HTTP POST request to /structr/rest/reset-password
with the following body:
fetch("http://localhost:8082/structr/rest/reset-password", {
method: "POST",
body: JSON.stringify({
eMail: "user.name@mail.com"
})
})
The reset password process would then send a mail using the above templates.
Notes:
- A resource access grant must be configured for public users to allow the POST method to the grant with signature
_resetPassword
- the configuration setting
JsonRestServlet.user.autologin
must be set to true to enable auto-login with the link in the email - the link in the mail is only valid once
Authentication
Once users have been created or signed-up, they may be able to login to a Structr application, or if they have been granted administrative permissions, to Structr’s admin UI. In the early stages of development of an app, you might
Authentication - JSON Web Tokens
Structr provides authentication and authorization with JSON Web Tokens (JWTs). You can get more information about how to work with JWT here
Structr currently supports signing and verifying JWTs with either a secret key or a private/public keypair stored in a Java KeyStore file.
JWT - With Secret Key
To use JWTs with a secret key you have to edit the follow Structr configuration settings:
key | value |
---|---|
security.jwt.secrettype | secret |
security.jwt.secret | [your secret key with at least 32 characters] |
JWT - With Java KeyStore
When you want to sign and verify your JWTs with a private-public keypair you first have to create a Java KeyStore file that contains your keys.
You can create a new Keypair in a new KeyStore file with the following example keytool
command:
keytool -genkey -alias jwtkey -keyalg RSA -keystore server.jks -storepass jkspassword
The KeyStore file has to be stored beside the structr.conf file in the installation directory of your Structr instance.
To use JWTs with a KeyStore file you have to edit the following Structr configuration settings:
key | value |
---|---|
security.jwt.secrettype | keypair |
security.jwt.keystore | [The name of your KeyStore file] |
security.jwt.keystore.password | [The password to your KeyStore file] |
security.jwt.key.alias | [The alias of the key in the KeyStore file] |
JWT - Create Token
Structr creates JWT access tokens with a simple request to it’s token resource. With each access token a new refresh token is created aswell, that can be used to obtain further access tokens without the need to send the actual user credentials as authentication.
The tokens are provided in the response body of the request to the token resource and they are stored as HttpOnly cookies in the browser.
The expiration time of the access- and the refresh-token and the issuer field of the JWTs can be adjusted in the configuration settings.
key | value |
---|---|
security.jwt.jwtissuer | Defaults to ‘structr’ |
security.jwt.expirationtime | Defaults to 60 minutes |
security.jwt.refreshtoken.expirationtime | Defaults to 1440 minutes |
An example would look like this
fetch("http://localhost:8082/structr/rest/token", {
method: "POST",
body: JSON.stringify({
name: "admin",
password: "admin"
})
})
For this request to work a resource access grant with the signature _token
has to exist and must be configure to allow POST
requests for all users.
will return the data:
{
"result": {
"access_token": "[THE ACCESS TOKEN THAT CAN BE USED FOR AUTHENTICATION]",
"refresh_token": "[THE REFRESH TOKEN THAT CAN BE USED FOR FURTHER AUTHORIZATION]",
"expiration_date": "1597923368582",
"token_type": "Bearer"
},
"result_count": 1,
"page_count": 1,
"result_count_time": "0.000041704",
"serialization_time": "0.000166971"
}
To create new access tokens you can either send the request above with the usercredentials or you can send the refresh token in the request header refresh_token
. An example request would look like this:
fetch("http://localhost:8082/structr/rest/token", {
method: "POST",
headers: {
"refresh_token": "REFRESH TOKEN"
}
})
Token Lifetime
The created access_token is valid until:
- The
expirationtime
is exceeded. - The token itself is revoked.
- The
refresh_token
that was created with the token is revoked. - A new token is created.
The created refresh_token is valid until:
- The
expirationtime
is exceeded. - The token is revoked.
JWT - Authenticate with JWT
To authenticate a request to any Structr ressource with a token you have two options:
- Send the
access_token
cookies stored by Structr (will be sent automatically by the browser) - Send the access token in the HTTP request header as Bearer token
An example request with the Authorization
request header would look like this:
fetch("http://localhost:8082/structr/rest/User", {
method: "GET",
headers: {
"authorization": "Bearer [ACCESS TOKEN]"
}
})
Authenticating - JWKS Provider
Structr also supports JWT validation with tokens issued by other authentication systems than Structr like e.g Keycloak or Auth0 via the open .well-known JWKS endpoints of those services.
To activate this feature, the configuration entry ‘security.jwks.provider’ has to be configured with the endpoint of the service. After this, Structr will verify a send token in the Authentication Header of the requests against the configured service.
Authentication - Login
A user can log into the application with an HTTP POST request to the REST interface of Structr. In response Structr will return a cookie with key JSESSIONID
and a new session id as value. A browser will send this session id automatically in subsequent requests to Structr where it can be used to run the request in the context of the logged in user.
The URL for the request
http[s]://domain[:port]/structr/rest/login
with payload
{
"eMail": "username",
"password": "password"
}
A sample curl request will look like this
curl --request POST \
--url http://localhost:8082/structr/rest/login \
--header 'content-type: application/json' \
--data '{
"eMail": "admin",
"password": "admin"
}'
For this request to work a resource access grant with the signature _login
has to exist and must be configure to allow POST
requests for public users.
Authentication - Logout
To be logged out of the system it is sufficient to make an HTTP POST request without payload to the URL:
http[s]://domain[:port]/structr/rest/logout
For this request to work a resource access grant with the signature _logout
has to exist and must be configure to allow POST
requests for authenticated users.
Authentication - Request Headers
As an alternative to obtaining a sessionId or a JWT, the username and password of a user can be sent to Structr in every request with two separate request headers.
This poses a potential security risk and should only be used over secure connections - either in a VPN or via HTTPS.
x-user: 'username'
x-password: 'password'
A request will look like this:
curl --request POST \
--url http://localhost:8082/structr/rest/User \
--header 'x-password: admin' \
--header 'x-user: admin'
OAuth
Additionally to the built in authentication system, Structr also supports OAuth authentication through various providers.
- Github
- Auth0
For more information about the logic behind OAuth, the following link can give a good overview how the implementation is done.
Global Settings
The following description will give an overview over the settings, that have to be entered in the structr.conf file via Structr’s configuration servlet. The description is given for the Auth0 specific settings, however they’re also valid for any other OAuth providers.
Triggering the Authentication
Key | Description |
---|---|
oauth.auth0.client_id | ClientId at provider. |
oauth.auth0.client_secret | Client Secret at provider. |
oauth.auth0.authorization_location | Redirect URI for the authentication process. |
oauth.auth0.token_location | Token URI of provider, called by Structr to optain access_token. |
oauth.auth0.redirect_uri | Called by provider on Structr application after successfull authentication. Triggers Structr to load userdata. |
oauth.auth0.user_details_resource_uri | URI of Oauth provider for user details e.g. username, eMail etc. |
oauth.auth0.error_uri | Error URI within Structr app. |
oauth.auth0.return_uri | Success URI called after successfull login. The resource of this URI usally is a landing page within your Structr application. |
jsonrestservlet.user.autocreate | Has to be set to enabled, so Structr can create usernode if they doesn’t exist yet. |
The authentication with the configured provider can be triggered by redirecting the user to the link /oauth/<provider>/login
. For Auth0 the link would be /oauth/auth0/login
.
To redirect the user to this location, the simplest way is to add an anchor HTML tag to your webapplication with the href
attribute set to the location.
<a href="/oauth/auth0/login">Login with Auth0</a>