Skip to main content
Skip table of contents

HCMS support for external session

Details about cookie-based session support via external webhook.

By its very design, Headless CMS is a purely stateless REST API without any HTTP session support. It is, however, possible to configure it to participate in a session provided by some other application component. In such setup, HCMS requests can gain additional permissions based on the active session.

Prerequisites

  1. The session management (including any necessary login, logout, idle detection, etc.) is implemented in a different application / component.
    • The expectation is that such application already exists (in a form of a Web CMS, usually).
    • In the present documentation, this application / component is referred to as Session Manager.
  2. The Session Manager provides a corresponding simple API endpoint, further referred to as webhook.

Warning This application is not provided by censhare as a part of the HCMS distribution.

  1. Both Session Manager and HCMS are available on the same domain and thus share the same cookie.
    • This is usually implemented by using a reverse proxy or load balancer (typical examples: haproxy, nginx, AWS ALB, F5, etc.).

Basic flow

  1. The user (browser) obtains cookie from the Session Manager.
    • This typically involves some kind of a login process, which is out of scope for this documentation and HCMS in general.
  2. Each HCMS request from the browser also sends the cookie (as long as the domain is the same, as stated above).
  3. HCMS detects that the configured cookie has been provided and asks the Session Manager for the session information.
    • This is done by invoking the configured HTTP endpoint, which Session Manager must implement. The cookie value is passed to this endpoint.
  4. Session Manager must check whether a session exists for the given cookie value and return this information to HCMS.
    • If the session exists, the answer should also contain any additional authentication and authorization information. Two options independent options are possible here:
      • In the form of claims, compatible with the standard JWT practices.
      • As a full access_token from OAuth2/OIDC identity provider, which is then internally added as an Authorization: Bearer header.
  5. Depending on if the session is valid or not:
  • if it's valid, HCMS fills additional request variables and assigns new roles based on the configuration;
  • if the session is invalid, expired, or there is no session to start with, the request processing continues. That is important because usually some data is available even before the login (for example, a company logo). Note that it is still possible that some other authentication mechanism is provided.

The name of the session cookie and the webhook endpoint must be specified in the '→HCMS configuration' (those are the only required parts).

Supported protocols

There are two variants of the protocol:

  • the simple one using the GET method and no encryption
  • the far more complex one using the POST method and an encryption.

Due to its simplicity, the unencrypted GET method may be easier for prototyping and other non-productive purposes. It also consumes less CPU. On the contrary, encryption should be your choice for a secure production environment, but you'd need to plan enough CPU capacity on your server.

In the HCMS configuration, you do not need (and also cannot) to explicitly specify which method you want to use - GET or POST, but if you specify an encryption, the configuration will switch to the POST method. See below for '→more information'.

The '→basic configuration', including the endpoint URL, is the same for both methods.

Why encrypt: possible attacks

From the security point of view, several types of attacks are possible and should be taken into consideration.

Passive attacks:

  • eavesdropping for the cookie: an attacker can gain the session cookie and use it to gain access
  • eavesdropping for the session info: an attacker can obtain sensitive values and then continue with the next attacks

Active attacks:

  • against webhook: an attacker can trick the Session Manager into providing sensitive values that can be abused in other contexts
    • This is particularly easy if the webhook is accessible from the frontend (browser javascript).
  • against HCMS: by tricking HCMS to call a fake system (network redirect, MITM attack), an attacker can gain additional privileges.

Unencrypted protocol (GET)

This option is very simple and easy to configure (it does not require anything except the cookie name and the endpoint URL) and debug, but inherently insecure: both HCMS and the endpoint grant a complete trust to the communication channel and to each other.

Warning: do not use this option without TLS (ie https://) to ensure at least basic defense against basic eavesdropping and some redirection attacks. Most of the attacks mentioned above, however, are still possible even with https! For this reason, it is recommended to not use this variant in production, ever.

The data flow for this option is the following:

  1. HCMS invokes the HTTP GET method, with the configured cookie forwarded in a standard HTTP way (ie Cookie header).
  2. The webhook must respond with the HTTP status 200 and JSON response body (application/json).
    • Anything else is considered a failure and results in the "failed, no session" status.
  3. The response body is parsed as a JSON object and validated according to the session-webhook-response-schema.json.
    • A failure to parse or to conform to the schema is considered an invalid response and results in the "failed, no session" status.
    • Note that the response must include the property "id" with a non-empty string value. This is a session ID and is always mandatory. You will find a detailed description below.
  4. If the response is valid (none of the previous steps failed) and contains a Set-Cookie header, then this header is propagated to the HCMS response.
    • This is important to refresh the session cookie and avoid session expiration.
  5. Based on the "authData" and "authorized" properties, the request can gain additional roles. Please see below for more information.

JWT / JWE Encryption Based Protocol (POST)

Both encryption and trust can be achieved by using the JWT = JSON Web Token Standard, in particular the JWE. In this variant of the protocol, both sides send an encrypted token which the other side must validate.

Two types of encryption are supported for now. This will be discussed below in more detail in the '→configuration section'.

The flow in this case is the following:

  1. HCMS invokes the HTTP request as a POST method, passing the cookie value inside an encrypted token.
    • The content type is text/plain; character encoding ASCII or UTF-9 (there is no difference, the JWT canonical form is pure ASCII)
    • The cookie is passed as a special non-standard claim cs:cookies, its value is an array of strings.
      • Each string in the value is a cookie encoded the same way as Cookie or Set-Cookie header, that is: name=value
    • The token has a short (one minute) expiration time claim exp and a random jti claim.
    • The token can also have an iss or aud claims set, but only if explicitly configured.
    • If the special configuration flag use-cookie-header is enabled (use-cookie-header="true"), the request also contains the Cookie header with the same cookie.
      • This is often necessary if the session management is done by some kind of a standardized HTTP server (Servlet Container, ISS, etc.).
      • Note that is it important to have a proper encrypted communication channel (https), otherwise the cookie might leak!
  2. The webhook (Session Manager) receives the token, decrypts it and checks its validity.
    • If the body is not a valid token at all, the response can be a simple error (the HTTP status 400 or similar is the clear choice).
    • If the token is a valid token, but cannot be decrypted, it is also allowed to return an HTTP error. For better defense against so-called "oracle" attacks, however, it is recommended that the response is HTTP 200 with encrypted token (see the next steps).
  3. The webhook checks and validates all claims.
    • In particular, the exp claim must be always present and the timestamp must be in the future.
    • Whenever possible, the implementation should store jti of each token and refuse to accept the same value again (to avoid replay attacks). Alternatively, it can store the whole token.
    • The implementation can, optionally, also validate the aud and/or iss claims. Note that they are present only when explicitly configured in the HCMS configuration.
    • In any case, the cs:cookies must be present and contain at least one valid cookie.
      • The implementation is allowed to accept both array of string or one single string, but no other data formats.
    • If any of these validations fail, the webhook must create a valid reply token, encrypt it and return by the HTTP 200 text/plain response.
      • The error can be present in the cs:error claim (string). The cs:result claim must be missing. The cs:request claim must contain the full request JWT token.
      • It is crucial that a random eavesdropper or active attacker without decryption key cannot distinguish this error reply from a standard, valid reply.
  4. The webhook checks if the cookie value in the request token represents a valid session.
    • If the request also contains the Cookie header (this must be enabled in the HCMS configuration), the values must be exactly the same.
      • If they are not, the request must be considered invalid, because it is probably a replay attack attempt.
    • If the session is present and valid, the session info is assembled as a JSON conforming to a session-webhook-response-schema.json. This is the same data structure as used by the simple GET protocol.
  5. The webhook creates a response JWT token and sends it as an HTTP 200 response body, with the type text/plain.
    • The token must have an expiration time (the exp claim) set. Recommended value is less than 1 minute in the future.
    • The token must have a special non-standard claim cs:request and its value (string) must the request JWT token (that is, the POST request body).
    • If the session is valid, the token should contain the cs:result claim. This claim must be the valid session info JSON object (see next section).
    • The token may contain a special claim cs:error with a string description of an error.
  6. HCMS receives the response and decrypts the token.
    • If the decryption fails, the signature does not match, the token is expired or invalid in any other way, the result is "failed, no session".
    • If the token does not contain cs:request or it is not exactly the same as the request from step 1, the result is also "failed, no session".
    • If the token contains the cs:cookies claim and it is a valid array of strings (or one single string), cookies are parsed from this claim. Any parsing error means that the whole token is considered invalid.
    • If the token does contain the cs:result claim and it can be correctly parsed, the response is considered valid and the result is "session present".
      • Note that the response must include the property "id" with a non-empty string value. This is a session ID and is always mandatory.
  7. If the response is valid, the session info and new cookies are processed.
    • Based on the "authData" and "authorized" properties, the request can gain additional roles. See below for detailed information.
    • If the token contains a valid cs:cookies claim, this cookie (or cookies) is added to the final HCMS response as the Set-Cookie header.
      • This is important to refresh the session cookie and avoid session expiration.
    • If the special configuration flag accept-set-cookie-header is enabled (accept-set-cookie-header="true") and the webhook response contains the Set-Cookie header, the new updated cookie is also set in the final HCMS response.
      • In case both token and the response contain the same cookie, the value from the token has precedence and the HTTP one is ignored.
      • Note that it is important to have proper encrypted communication channel (https), otherwise the cookie might leak!
      • In conjunction with use-cookie-header, this allows Security Manager to completely rely on the session management implemented in a standard HTTP server.

Session info data format

Regardless of which option you use - with GET or with POST - if the session is valid, the session info format is the same. This format is validated by a session-webhook-response-schema.json. It contains the following properties:

  • "id": required, session ID
    • Must be a non-empty string.
    • Note that this ID should not be the same as the cookie value.
  • "createdAt": an optional timestamp of the session begin
    • String in the standard ISO 8601 timestamp format.
    • For compatibility, a number is also accepted and interpreted as a UNIX or Java timestamp (ie number of seconds or milliseconds since 1970-01-01) based on its value. This variant is not recommended.
  • "expireAt": current expiration timestamp (when the session ceases to exist)
    • The same format as createdAt
    • Note that the session is usually prolonged on each valid request, but this is not a strict requirement. It is up to Session Manager to make such decisions.
  • "authenticated": an optional flag saying whether the session is authenticated or anonymous
    • When missing, the true value is assumed if the "authData" property is present.
    • In the current implementation, this flag has only one effect: when explicitly set to false, the "authData" property is ignored even when present.
    • Note that even the non-authenticated (anonymous) session is still considered valid session, as long as the "id" exists.
  • "authData": optional authentication/authorization data
    • Missing when the session is unauthenticated (anonymous). Ignored when "authenticated" is set to false.
    • Must be a JSON object, but all properties are optional:
      • "access_token": standard OpenID Connect, expected to be in the JWT format
        • When present, HCMS adds its value as a synthetic ("fake") request header in the standard Authorization: Bearer form. This header is then picked and handled by the standard JWT authorization handler.
        • Recommendation for Session Manager implementation: fill this property only when it's actually needed. Otherwise, put the parsed claims to the "claims" property instead.
      • "id_token": a standard OpenID Connect id_token; unused, reserved for future use
      • "claims": a JSON object with theoretically any values
        • The intended use is to put parsed claims from the JWT token (typically id_token or access_token), so HCMS does not need to parse them.

Minimal example (anonymous session):

JSON
{
    "id": "dFdlSVC5XzyOwRlyjeXoLW6dZxNZHJnO"
}

Full example (session authorized by Keycloak):

JSON
{
    "id": "dFdlSVC5XzyOwRlyjeXoLW6dZxNZHJnO",
    "createdAt": "2024-03-05T08:30:52.130Z",
    "expireAt": "2024-03-05T08:41:02.203Z",
    "authenticated": true,
    "authData": {
        "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI1X2xWNHBTTHVXeHFmYjNYV2tSUmJKQXF1UmRiODNNaXMydzA0ZXl5MlRFIn0.eyJleHAiOjE3MDk2Mjc3NjIsImlhdCI6MTcwOTYyNzQ2MiwiYXV0aF90aW1lIjoxNzA5NjI3NDQxLCJqdGkiOiIxOTVhOWMxZi1kMjdhLTQ0ZDItODUyMC1lZWU1YTdjMjhkZTUiLCJpc3MiOiJodHRwczovL2F1dGgtZGV2LmNlbnNoYXJlLmNvbS9hdXRoL3JlYWxtcy9ldmVsb3AtbmV3LWIzLWZ1dHVyYW1hLWRldi1ueC1jZW5zaGEiLCJhdWQiOlsiZXRzIiwicmVhbG0tbWFuYWdlbWVudCIsImFjY291bnQiXSwic3ViIjoiMjAwZTBlNjYtZDgwMy00ZTBlLThjMWItZDRjMTJiZWQyM2NmIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiZXRzIiwic2Vzc2lvbl9zdGF0ZSI6ImU1NzU5OTA2LWMzNWMtNDE5NC04ODZiLWZmMmY1MmIzYzQwZCIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJldHNfYWRtaW4iLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsicmVhbG0tbWFuYWdlbWVudCI6eyJyb2xlcyI6WyJ2aWV3LWlkZW50aXR5LXByb3ZpZGVycyIsInZpZXctcmVhbG0iLCJtYW5hZ2UtaWRlbnRpdHktcHJvdmlkZXJzIiwiaW1wZXJzb25hdGlvbiIsInJlYWxtLWFkbWluIiwiY3JlYXRlLWNsaWVudCIsIm1hbmFnZS11c2VycyIsInF1ZXJ5LXJlYWxtcyIsInZpZXctYXV0aG9yaXphdGlvbiIsInF1ZXJ5LWNsaWVudHMiLCJxdWVyeS11c2VycyIsIm1hbmFnZS1ldmVudHMiLCJtYW5hZ2UtcmVhbG0iLCJ2aWV3LWV2ZW50cyIsInZpZXctdXNlcnMiLCJ2aWV3LWNsaWVudHMiLCJtYW5hZ2UtYXV0aG9yaXphdGlvbiIsIm1hbmFnZS1jbGllbnRzIiwicXVlcnktZ3JvdXBzIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50Iiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSIsInNpZCI6ImU1NzU5OTA2LWMzNWMtNDE5NC04ODZiLWZmMmY1MmIzYzQwZCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwidXNlcl9uYW1lIjoiZGV2c2VhdDEiLCJhY2Nlc3Nfcm9sZSI6ImFkbWluIiwibmFtZSI6ImRldiBzZWF0MSIsInByZWZlcnJlZF91c2VybmFtZSI6ImRldnNlYXQxIiwiZ2l2ZW5fbmFtZSI6ImRldiIsImZhbWlseV9uYW1lIjoic2VhdDEifQ.BnDgAd0sBmwbvr3h6ivU40BhWzON3nONaqLFF9OLmY3FGhw4m1Y-R62QQF7xWqbKJCec7DB3VUmKJylJ_o0H8SuBnVntqyNRNXmtsEcEpkuwvWArJKK1A3CE8j0JRblusHzv3W3j709H7cDL0cVPgraxw16lnnvCvM2nCSRw8WkLY3fFPPr2GEbtz2b82QKFPa8wQNZQS1F32W7a22vACVL2Z3t40YOmouRWybNkmOsqU4O1l4fQd9FD7EpdFot4HZ4IVvgefkUrhwGox9Bv_HNEqLrxfNYkYw7-wMpkvFQDr5j75_FSjgVcweKFOS1OlfSOFZKl-07ixcl7tmvc_Q",
        "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI1X2xWNHBTTHVXeHFmYjNYV2tSUmJKQXF1UmRiODNNaXMydzA0ZXl5MlRFIn0.eyJleHAiOjE3MDk2Mjc3NjIsImlhdCI6MTcwOTYyNzQ2MiwiYXV0aF90aW1lIjoxNzA5NjI3NDQxLCJqdGkiOiI1MDlhZDAyMC04OTE4LTRkYmItYTk1Ny1lNjk5NzQ4YjVkMzUiLCJpc3MiOiJodHRwczovL2F1dGgtZGV2LmNlbnNoYXJlLmNvbS9hdXRoL3JlYWxtcy9ldmVsb3AtbmV3LWIzLWZ1dHVyYW1hLWRldi1ueC1jZW5zaGEiLCJhdWQiOiJldHMiLCJzdWIiOiIyMDBlMGU2Ni1kODAzLTRlMGUtOGMxYi1kNGMxMmJlZDIzY2YiLCJ0eXAiOiJJRCIsImF6cCI6ImV0cyIsInNlc3Npb25fc3RhdGUiOiJlNTc1OTkwNi1jMzVjLTQxOTQtODg2Yi1mZjJmNTJiM2M0MGQiLCJhdF9oYXNoIjoiM0RnX0dCSWNVVkVMQkI2MklBOV9UUSIsInNpZCI6ImU1NzU5OTA2LWMzNWMtNDE5NC04ODZiLWZmMmY1MmIzYzQwZCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwidXNlcl9uYW1lIjoiZGV2c2VhdDEiLCJhY2Nlc3Nfcm9sZSI6ImFkbWluIiwibmFtZSI6ImRldiBzZWF0MSIsInByZWZlcnJlZF91c2VybmFtZSI6ImRldnNlYXQxIiwiZ2l2ZW5fbmFtZSI6ImRldiIsImZhbWlseV9uYW1lIjoic2VhdDEifQ.UdecPJKNz7h6CnnjbcH9j5GhETENk-uMmCpKgBkIlS4h9UiDFXQc3_6nvoAKoi9U5L_4jFQUEKUkK3BVAJwndSOa2yR0occG038J6z3qUTeufJf21YSl2TqrcvNNsWr4AOw9UgofhqwhhDjivdyAM8ejyuStxIqKiOJaG4egqUsYjbXv_F7mYAbUTvB78mPRtUcOdINGURAKlMUw_tgqhtRxlaTdJlY1gZyavBu_EUkCDXyXcY8Wh5Yn1mSEA9UUAnmWUBsTepxX7uGvLKV4l9NcFGRlL8q0GEEVk55aqK2xz7Aa7P9axjYIzQsS3TOfQpHD3CppQMXR5n6Hob9rEg",
        "claims": {
            "iat": 1709628039,
            "auth_time": 1709627441,
            "jti": "cc8fbf37-3952-4b32-850f-0239a5053868",
            "iss": "https://auth-dev.censhare.com/auth/realms/evelop-new-b3-futurama-dev-nx-censha",
            "sub": "200e0e66-d803-4e0e-8c1b-d4c12bed23cf",
            "azp": "ets",
            "session_state": "e5759906-c35c-4194-886b-ff2f52b3c40d",
            "sid": "e5759906-c35c-4194-886b-ff2f52b3c40d",
            "email_verified": false,
            "user_name": "devseat1",
            "access_role": "admin",
            "name": "dev seat1",
            "preferred_username": "devseat1",
            "given_name": "dev",
            "family_name": "seat1"
        }
    },
    "loggedInAt": "2024-03-05T08:31:02.055Z"
}

General HCMS Configuration

Session management is considered an auth provider. Its configuration is stored in the HCMS configuration, inside the <auth> element and is named <session>.

The configured session management configuration includes three distinct parts:

  • One or more <cookie name=""> elements (mandatory): the session cookies
    • Usually there is only one session cookie, but it is possible to configure several.
    • The attribute name is required and cannot be empty.
  • Exactly one <webhook> element.
    • Exactly one sub-element <url>, with the endpoint URL as its value.
      • An optional, but strongly recommended attribute: timeout = timeout in milliseconds.
      • One of the JWT encryption elements: optional
        • When no encryption is specified, the simple (and insecure) '→GET protocol' will be used.
        • If you want to use an encryption, you need to configure one of the elements - <jwe-dir> or <jwe-jws-pki> - as '→described below'. In this case, the configuration switches to the '→POST method'.
      • Zero or more <header name="" value=""/> elements.
        • These headers are always added to each webhook request. Their values are hardcoded.
      • An optional <cache> element: when present, it enables burst cache of the webhook results. The cache uses cookie value(s) as a key and the webhook invocation result as a value.
        • Attribute size, required: cache size, maximum number of cookie values to keep in memory. Set it to negative to disable the cache.
        • Optional attribute expiration: cache expiration time in milliseconds. Default is 300ms.
        • This cache improves performance in case of burst requests and improves resilience against DOS attacks, but enables time window when user can access data even after logout.
          • For this reason, the expiration time below 1000 (one seconds) is recommended.
  • Exactly one <claims> element. It defines how is the session info processed in case of a valid session.
    • Similar to the <jwt> auth provider configuration, it processes "claims" from the webhook response.
    • The attributes jwt-base-attributes and roles-claim-separator are exactly the same, with the same defaults.
      • This means that, by default, the claim "roles" directly contains HCMS roles.
    • Elements <user-lookup>, <role> and <blacklist> are also the same.
      • This means that, by default, if the value of the sub claim can be parsed as a valid positive integer, it is interpreted as an asset id.

Example:

XML
<auth>
  <session>
    <cookie name="session.sid"/>
    <webhook>
      <url timeout="1000">https://to.be.replaced/bff/session/sessioninfo</url>
    </webhook>
    <claims>
    </claims>
  </session>
</auth>

JWT encryption configuration

jwe-dir: simple AES encryption with shared keys

Both request and response tokens are encrypted following the AES in the so-called "Direct Encryption Key Management Mode", as defined in ERC 7516. In this mode, both encryption keys are directly stored in the HCMS configuration.

Algorithms used by this method provide both encryption and message with an authenticity while imposing a very little overhead on a modern CPU. The main disadvantage is the danger of leaked keys since the same keys must be provided in both configurations.

Configuration:

  • Attribute algorithm, required: one of the standard encryption algorithms. Only algorithms that provide message authenticity are allowed.
    • The algorithm can be either "AES CBC with MAC" (A128CBC-HS256, A192CBC-HS384 or A256CBC-HS512) or AES in the Galois/Counter mode (A128GCM, A192GCM or A256GCM).
  • Optional attribute debug: when set to true, a detailed information about webhook invocation and in particular about failures is written to the HCMS log.
    • This is very useful in a development environment, but potentially dangerous in production.
  • Optional headers use-cookie-header, accept-set-cookie-header, issuer and audience are explained in the protocol section above.
  • Element <request-key>, required: contains the AES key used to encrypt the request token, as a hexadecimal number.
    • The length must be exactly the correct number of digits for the specific algorithm: 32 (A128GCM), 48 (A192GCM), 64 (A256GCM or A128CBC-HS256), 96 (A192CBC-HS384) or 128 (A256CBC-HS512).
  • Element <response-key>, required: contains the AES key used to decrypt the response token, as a hexadecimal number.
    • The length must be exactly the correct number of digits for the specific algorithm, just like in the case of request-key.
    • You can have multiple <response-key> elements to enable key rotation. Let's say, both sides (HCMS and Session Manager) run multiple instances in a cloud environment. In a nutshell, the key rotation does the following:
      • The key A is used;
      • After some time, it is time for a new one, let's say B
      • Configuration on both sides is changed to use B for encryption and accept both B and A
      • The new configuration is applied via rolling restart (sometimes also called A/B deployment or blue/greed deployment)
      • During that time, both the old configuration and the new configuration are applied at the same time; which means that each side can randomly receive token encrypted by A or B, but both must be accepted
      • When the rolling update is done, all running instances use only the key B for encryption; as a consequence, the key A is no longer needed, and a different configuration applied again (and it does not supported the key A)

Example for a simple AES encryption with shared keys:

XML
  <session>
    <cookie name="session.sid"/>
    <webhook>
      <url timeout="1000">https://to.be.replaced/bff/session/sessioninfo</url>
      <jwe-dir algorithm="A256CBC-HS512" debug="true" use-cookie-header="true" accept-set-cookie-header="true">
        <request-key>d9cc3ff561adf59bf60f9fe7b9831c33eefe38a8afc3f79dd3c7f0dd3c24982b5230d67bc82e8f0ba0ff086ebc25801656075e193c5aadd793bd8fd4d4b21832</request-key>
        <response-key>891a3ff561adf59bf60f9fe7b9831c33eefe38a8afc3f79dd3c7f0dd3c24982b5230d67bc82e8f0ba0ff086ebc25801656075e193c5aadd793bd8fd4d4b218ab</response-key>
      </jwe-dir>
    </webhook>
    <claims/>
  </session>

jwe-jws-pki: asymmetric cryptography with RSA or EC keys

Both request and response are the so-called "nested" tokens as defined by RFC 7519: first, the claims are signed by JWS signature with the private key, then the resulting JWT representation is encrypted by the peer's public key. Each side has its own private key and the public key of the other side, so they can always ensure both confidentiality and trust.

The main advantage is that each private key is present only in a single configuration, while the other side of the communication has just the public key. This reduces the chance of key leaks. In addition, the cryptographic strength is generally considered better compared to the AES cipher (although that might change in time).

On the other hand, the encryption and decryption consumes significantly more CPU, which might lead to a high CPU usage and potentially even Denial of Service.

Configuration:

  • Attribute algorithm, required: one of the standard encryption algorithms.
    • The algorithm can be either "AES CBC with MAC" (A128CBC-HS256, A192CBC-HS384 or A256CBC-HS512) or AES in the Galois/Counter mode (A128GCM, A192GCM or A256GCM).
  • Attribute key-algorithm, required: one of the standard encryption algorithms, as defined in the corresponding RFC.
    • Only one RSA algorithm is supported: RSA-OAEP-256 (RSA-OAEP is already considered weak in 2023)
    • Several Elliptic-key algorithms are supported: ECDH-ES+A128KW, ECDH-ES+A192KW and ECDH-ES+A256KW (see RFC 7518 for details)
  • Attribute signature-algorithm, required: one of the standard signature algorithms, as defined in the corresponding RFC.
    • RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512
  • Optional attribute debug: when set to true, a detailed information about webhook invocation and in particular about failures is written to the HCMS log.
    • This is very useful in a development environment, but potentially dangerous in production.
  • Optional headers use-cookie-header, accept-set-cookie-header, issuer and audience are explained in the protocol section above.
  • Element <hcms-private-key>, required: the private key used to sign the claims and decrypt the response.
    • It must be in the PEM format either directly in the element body, or in a file specified by an attribute file
  • Element <webhook-public-key>, required: the public key used to encrypt the result and validate the response signature.
    • It must be in the PEM format either directly in the element body, or in a file specified by an attribute file

Note that the same algorithms are used in both directions, so both key pairs must be of the same type (RSA or EC).

Example for asymmetric cryptography with RSA or EC keys with RSA keys:

XML
  <session>
    <cookie name="session.sid"/>
    <webhook>
      <url timeout="1000">https://to.be.replaced/bff/session/sessioninfo</url>
      <jwe-jws-pki key-algorithm="RSA-OAEP-256" algorithm="A256CBC-HS512" signature-algorithm="RS512"
           debug="true" use-cookie-header="true" accept-set-cookie-header="true">
        <hcms-private-key file="/tmp/sender.2.private.pem"/>
        <webhook-public-key file="/tmp/receiver.2.public.pem"/>
      </jwe-jws-pki>
    </webhook>
    <claims roles-claim-name="roles">
      <role>whoami</role>
      <role claim-name="resource_access" claim-regex=".*account.*">schema-ro</role>
    </claims>
  </session>

Example for asymmetric cryptography with RSA or EC keys with Elliptic keys:

XML

<session>
  <cookie name="session.sid"/>
  <webhook>
    <url timeout="1000">https://to.be.replaced/bff/session/sessioninfo</url>
    <jwe-jws-pki key-algorithm="ECDH-ES+A256KW" algorithm="A192GCM" signature-algorithm="ES384"
                 debug="true" use-cookie-header="true" accept-set-cookie-header="true">
      <hcms-private-key>
        -----BEGIN EC PRIVATE KEY-----
        MIGkAgEBBDCrzINGMIAhJ21HeI5uSKO1PJ3j19hmeDJH5vCbXTvqDPpTOO3Rb23c
        5y+b3Eq0d4+gBwYFK4EEACKhZANiAARs4jOutus8zIpxUGjHJVRqELYW4Y8xRVQZ
        u8aeju9plT6XuujX1J6xe5LcLLBiaPCfeUvV/nAZYqzYGUmlTOH/oe1ZodQ9NSJU
        4wOiAd2/fNr0c7xhLeAbTS11oiGCUpE=
        -----END EC PRIVATE KEY-----
      </hcms-private-key>
      <webhook-public-key>
        -----BEGIN PUBLIC KEY-----
        MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAERgozoBSNl07p8dizSa3TeaBSiM3MYgQO
        7qTEujXpT3Q984V5IHglDAyFEngrMc6TGIOdgaaQ4Us4D9gJJRPYH5AvQjHu+jji
        mmIowQM7S7AVfV/WRasEAnV6K7dU07eD
        -----END PUBLIC KEY-----
      </webhook-public-key>
    </jwe-jws-pki>
  </webhook>
  <claims roles-claim-name="roles">
    <role>whoami</role>
    <role claim-name="resource_access" claim-regex=".*account.*">schema-ro</role>
  </claims>
</session>

Generating keys HOWTO

When using the encrypted tokens protocol, both HCMS and the Session Manager must be configured with properly generated random keys. For detailed description of the available algorithms and the necessary keys, please consult RFC 7518 and/or any of its replacements and followups.

Many tools exist to generate these keys, but one tool in particular is very popular and de-facto the industry standard: openssl which is available as a commandline tool for all major platforms.

Below is an example for generating an AES key of a given size (64 bytes, suitable for A256GCM or A128CBC-HS256):

SHELL
openssl rand -hex 64 

For asymmetric cryptography, two steps are needed: first, the private key needs to be generated. Then the public key must be extracted from the private one.

Generating RSA key pairs is simple, because the only parameter is the number of bits - which is not actually limited by the algorithm selection. An example for 2048 bits:

SHELL
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -outform PEM -pubout -out public.pem
## now we have two PEM files: private.pem and public.pem

Generating Elliptic Curve is more complex, because the proper "curve" must be used, with parameters appropriate for the given algorithm. Example using the P-384 curve suitable for the ES384 algorithm:

SHELL
openssl ecparam -genkey -name secp384r1 -noout -out private.pem
openssl ec -in private.pem -pubout -out public.pem 

All curves supported by the openssl tool can be obtained by the option -list_curves:

SHELL
openssl ecparam -list_curves

change

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.