.. Relock Cloud Deployment documentation master file, created by sphinx-quickstart on Wed Aug 20 11:05:55 2025. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. .. rst-class:: break_before JavaScript Agent Integration ============================ This integration mode provides fully invisible, **behind-the-scenes** device identity verification. The JavaScript agent automatically starts a Relock gateway session and rotates the cryptographic keys during session lifetime. Key rotation is enforced both at the beginning of the session and periodically throughout its lifetime. Rotation at session start is enforced and required, durring the session liftime rekeying is enforced at fixed time intervals or even at every single request, depending on your security requirements. The frequency is configurable, ranging from every few minutes to each request for maximum assurance. Because this process runs silently in the background, users experience no interruptions or redirects, while the application maintains continuous device verification and strong session protection. Reverse Proxy Setup (Required) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Your reverse proxy must route all requests from ``/relock/*`` to ``https://relock.host/`` and include the header ``X-Key-Wildcard`` containing your unique client UUID. This UUID binds the requests to your specific gateway and ensures that Relock can properly verify the origin of each request. For security and reliability, make sure this header is added automatically to every forwarded request. Without it, the Relock gateway will reject or treat the session as untrusted. Detailed reverse proxy configuration examples (for both **Nginx** and **Apache**) are provided earlier in this document. Use those examples as a reference to set up your proxy correctly. .. rst-class:: break_before HTTP Strict Transport Security (HSTS) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Relock depends on the integrity of the browser’s origin enforcement. To prevent downgrade or redirection attacks, it is strongly recommended to enable **HTTP Strict Transport Security (HSTS)** on all domains that integrate Relock. HSTS instructs browsers to: - Always connect via **HTTPS** (never downgrade to HTTP). - Cache this rule for a specified duration. - Refuse connections with invalid or self-signed certificates. **Recommended configuration:** .. code-block:: bash Strict-Transport-Security: max-age=63072000; includeSubDomains; preload Where: - ``max-age=63072000`` enforces HTTPS for two years. - ``includeSubDomains`` applies the rule to all subdomains. - ``preload`` allows the domain to be added to browser preload lists for protection from the very first request. Using HSTS ensures that Relock’s origin-bound tokens and cryptographic proofs cannot be intercepted or stripped of TLS protection by downgrade attacks, DNS manipulation, or man-in-the-middle proxies. .. rst-class:: break_before Relock.js Library Integration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In this integration option, a lightweight **Relock JavaScript SDK (``relock.js``)** is required. The JavaScript file should be included in the ```` section of every page generated by your web application server to ensure it runs consistently. .. code-block:: html The behavior of the Relock agent differs slightly between Multi-Page Applications **(MPAs)** and Single-Page Applications **(SPAs)**. The distinction is important, because MPAs automatically reload the ```` on each navigation, while SPAs typically render views dynamically without reloading the entire page. The following sections explain the differences and provide guidance for integrating Relock depending on your application’s architecture. .. include:: nonces.rst Subresource Integrity (SRI) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Relock.js should always be loaded from **your own application domain** (e.g. ``https://example.com/relock/relock.js``), never from a third-party origin. This ensures that the script is covered by SameSite browser protections and cannot be substituted cross-site. For additional assurance, Relock Cloud provides an official SRI hash in the **Admin Panel**. You should copy this hash into your script tag so that the browser verifies the file contents even when served through your own reverse proxy: .. code-block:: html MPA Web Applications ~~~~~~~~~~~~~~~~~~~~ For non-SPA (Multi-Page Application) web applications, including ``relock.js`` in the **** section ensures the Relock agent is triggered automatically on every page load. The agent starts session validation and generates a fresh token and signature for each page relaod. On every page reload, new SamesSite 'lax' non-HTTP-only cookies are generated: ``X-Key-Token`` → A fresh, hex-encoded token derived from secret material. ``X-Key-Signature`` → An hex-encoded Ed25519 signature of the token. These cookies can be used for **GET request–level authentication** of the user’s device identity. In practice, the token and signature serve as a cryptographic proof of the browser’s identity, allowing your backend or microservices to validate that the request originates from a trusted device and legitimate browser sandbox. .. rst-class:: break_before Multi-Tab Browsing Support ~~~~~~~~~~~~~~~~~~~~~~~~~~ Relock natively supports multi-tab browsing without compromising security. Each browser tab is enumerated with a unique **tab identifier**. If a new tab is opened and the identifier changes, the Relock agent automatically invokes a fresh session agreement with the gateway by default. This ensures that: - SOTTs remain single-use and tied to the active tab context. - Tokens or session state cannot be replayed across tabs. - Race conditions between parallel requests in different tabs are avoided. From the user’s perspective, the experience is seamless: opening new tabs continues the session, but cryptographic material is refreshed to preserve origin binding and one-time-use guarantees. This mechanism prevents session artifacts from being replayed across tabs, ensures one-time-use guarantees remain intact, and eliminates potential race conditions between parallel requests. From the user’s perspective the experience is seamless, while security is preserved at request-level. .. rst-class:: break_before SPA Web Applications ~~~~~~~~~~~~~~~~~~~~ Single-Page Applications (SPAs) update the page content dynamically without reloading the entire page. Because the ```` section is not reloaded on navigation, the Relock agent must be manually notified whenever a view change occurs. This is achieved by triggering a custom JavaScript event called ``X-Key-View-Change``. You can dispatch the event as follows: .. code-block:: javascript let event = new CustomEvent('X-Key-View-Change', { bubbles: false }); window.dispatchEvent(event); Many JavaScript frameworks allow you to handle this automatically within their routing mechanisms. For example, in **Angular** you can listen for route changes and dispatch the event each time a navigation occurs: .. code-block:: typescript import { Router, NavigationEnd } from '@angular/router'; import { filter } from 'rxjs/operators'; constructor(private router: Router) { this.router.events .pipe(filter(event => event instanceof NavigationEnd)) .subscribe(() => { let event = new CustomEvent('X-Key-View-Change', { bubbles: false }); window.dispatchEvent(event); }); } .. rst-class:: break_before Key Established Event ~~~~~~~~~~~~~~~~~~~~~ Each time the view changes, ``Relock.js agent`` accesses the secret material and verifies the session state and if needed rotatates the symmetric key. The key rotation is not enforced always when the ``X-Key-View-Change`` event is fired except the session start. This operation usually takes a few milliseconds as it retrieves the secret material from storage and decrypts/rotates it. As ``Relock.js agent`` is asynchronus and if it started before the the ``DOMContentLoaded`` event the keys are typically available in browser memory before the web page is entirely processed. Depending on the user device computing power. Once the JavaScript agent triggers the ``X-Key-Established`` event, authentication token generation becomes available (during this event, cookies for ``GET`` requests are also created). .. code-block:: javascript window.addEventListener('X-Key-Established', async function (event) { let token = await window.relock.token(); let signature = await window.relock.sign(token); }); In addition, the Relock.js agent fires the ``X-Key-Rekeying-Done`` event whenever the re-keying or re-initialization process has finished. .. code-block:: javascript window.addEventListener('X-Key-Rekeying-Done', function (event) { console.log(event.detail); }); Both events have the same ``JSON`` payload containing information about the device authentication process and the resulting state. The ``Key-Established`` event fires only when the state of verification is successful. The event payload has a major key difference between the ``fresh`` and the ``state`` attributes: ``fresh`` → ``true`` only if the device has never interacted with the gateway before or storage was completly cleared. ``state`` → ``true`` if the gateway has decided to enroll new secret material and perform a fresh key agreement (e.g., after reset). .. rst-class:: break_before Established Event Payload ~~~~~~~~~~~~~~~~~~~~~~~~~ **Example JSON Payload:** .. code-block:: json {"fresh": false, // First-time interaction with the gateway? "valid": true // Was the secret validation successful? "state": false, // Was a new key agreement performed? "owner": false, // Device has assigned owner? "network": false, // Network location change? "authenticated": false, // Is the user authenticated? "status": "OK", // Human-readable status message "code": 200} // Operation status code **Attributes explained** ================= ======================================================= Field Description ================= ======================================================= ``authenticated`` Boolean. Indicates if the user is authenticated in the current session. ``code`` Integer. HTTP-like status code of the operation. ``fresh`` Boolean. ``true`` only for a device interacting with the gateway for the first time. ``state`` Boolean. ``true`` if a new key agreement was performed (e.g., re-keying failur or key collision). ``owner`` Boolean. ``true`` if a user was signed-in before and the device has an owner. ``owner`` Boolean. ``true`` if server-side reports network location change. ``status`` String. Human-readable description of the operation result. ``valid`` Boolean. ``true`` if the key validation was successful. ================= ======================================================= .. rst-class:: break_before Backend-Side Request Verification ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The web application backend can verify each incoming request using browser delivered cryptographic proofs, with the level of verification depending on the accepted risk of the request type. Typically, ``GET`` requests that do not change the application state do not need to be strongly authenticated — in such cases, proof of possession is sufficient. However, all ``POST`` requests, as well as ``GET`` requests with path parameters that could alter or expose web app data, should be validated by both **token** and **signature** verification. Below are examples of basic and advanced request-level authentication approaches. Basic Request Authentication ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Non-critical requests in a web application can be authenticated in a simple way by verifying the user device's signature. During secret material enrollment, the device public key becomes available as a property of the ``window.relock`` object. .. code-block:: javascript window.addEventListener('X-Key-Established', function (event) { console.log(window.relock.public); }); The device public key is hex-encoded and remains unchanged unless the secret material used for token generation is replaced. This public key can be securely stored by the backend application and used to verify signatures on each request (verification can be performed within milliseconds). **Security note:** If basic-level authentication is used, remember to implement token replay prevention. Replay prevention ensures that an attacker cannot capture a valid token from one request and reuse it to impersonate the client in subsequent requests. Your backend application should reject any request that attempts to reuse a token that has already been validated within the current session. Without replay protection, even a simple interception of traffic (for example, through a compromised network node) could allow an attacker to repeatedly replay the same token and gain unauthorized access despite the presence of signature verification. .. rst-class:: break_before Critical Request Authentication ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ All critical requests to your backend should be authenticated not only through a simple signature check, but also by validating that the token is derived from the current version of the secret material. The Relock gateway includes built-in token replay prevention by default. To verify both the token and its signature, your backend application must make an API call to the Relock confirmation endpoint. **Verification Endpoint:** .. code-block:: bash POST /relock/confirm If the request returns ``200 OK`` or ``407 Proxy Authentication Required``, the request can safely proceed. If it returns any other status, the request should be rejected and the authentication flow restarted. **JavaScript Example:** .. code-block:: javascript let token = await window.relock.token(); let signature = await window.relock.sign(token); let xsid = ""; // session ID, available as HTTP-only cookie // included to the request send to the backend return await fetch("/relock/confirm", { method: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json" }, body: JSON.stringify({ "X-Key-Token": token.hexlify(), "X-Key-Signature": signature.hexlify(), "X-Key-Session": xsid }) }).then((res) => res.json()); .. rst-class:: break_before Relock Gateway Status Codes ~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Relock Gateway Status Codes** =============================================== ======================================== Status Code Description =============================================== ======================================== ``200`` OK The token and signature are valid, and the user is signed in to the Relock gateway. The cryptographic assets are confirmed, and the gateway considers the session authenticated. ``407 Proxy Authentication Required`` The token and signature are valid, but the user is not currently signed in to the Relock gateway. This confirms that cryptographic verification succeeded, but indicates the web application has not yet invoked the Relock sign-in flow, so the gateway has no active authentication state. ``409`` Conflict The provided token does not match the server’s current version of the secret material. This usually means the client is using outdated or revoked secret material to derive the token. The request must be rejected immediately. ``417`` Expectation Failed The token signature is invalid. This means the token may have been tampered with or generated by an unauthorized client. The request must be rejected immediately. ``401`` Unauthorized The confirmation call does not contain a valid token and/or signature. This occurs when required authentication fields are missing or malformed. Every confirmation request must include both a valid token and signature. ``406`` Not Acceptable The gateway is awaiting re-keying confirmation and cannot currently verify the data. This occurs when the secret material is in the process of being rotated. The browser must complete the re-keying process before new tokens can be generated. ``404`` Not Found The device data does not exist in the current session. This may happen if the session has expired, if the device is unknown to the gateway, or if the session state has been reset. The client must re-authenticate to continue. ``410`` Gone The session no longer exists. This indicates the session has been explicitly terminated or has permanently expired. The client must establish a new session and repeat the authentication process. =============================================== ======================================== .. rst-class:: break_before Login and Logout a User in the Gateway ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signing a user in to the Relock gateway simplifies the authentication flow. After a successful login, future sessions can automatically recognize a returning user (the owner of the device). This feature helps reduce friction and minimize the cost of repeated MFA (Multi-Factor Authentication) prompts. The sign-in and sign-out API routes can be called from either the backend or frontend, depending on the web application’s architecture. However, backend API calls are generally recommended, as handling sensitive user data directly in the frontend may violate data privacy and compliance requirements. **API Routes:** /relock/login → Call after successful credential verification (e.g., password). /relock/logout → Call when a user signs out (no user ID required). **Example: ``/relock/login``** .. code-block:: javascript async login(user = String(), email = String(), xsid = String()) // session ID, available as an HTTP-only cookie // included in the request sent to the backend { let token = await window.relock.token(); let signature = await window.relock.sign(token); return await fetch("/relock/login", { method: "POST", credentials: 'include', headers: { "Content-Type": "application/json", "Accept": "application/json" }, body: JSON.stringify({ "X-Key-Token": token.hexlify(), "X-Key-Signature": signature.hexlify(), "X-Key-Session": xsid, "user": user, "email": email }) }).then((res) => res.json()); } Zero-Trust Remember-Me ~~~~~~~~~~~~~~~~~~~~~~ An additional benefit of having a signed-in user is the ability to implement a secure "remember me" feature. If the web application allows automatic logins for returning users, cookie-based login can be enhanced with device-level cryptographic proof of identity. In this scenario, the backend application should verify both the token’s authenticity and the device signature. If the ``remember me`` cookie is valid, the user can be signed in without requiring a full login flow. The backend should also track the time of the last session and decide whether to prompt for a password (or MFA) or to allow seamless auto-login. The gateway can also provide the information about remote address of user device and prevent automatic login if network location changes. **Example Implementation:** .. code-block:: javascript window.addEventListener('X-Key-Established', function (event) { if (event.detail.authenticated === false) { if (event.detail.fresh === true) { document.location = '/sign_on'; } else { if (event.detail.state === true) { document.location = '/login_input_and_mfa'; } else if (event.detail.owner && event.detail.network) { document.location = '/autologin'; } else if (event.detail.owner) { document.location = '/password'; } } } else { document.location = '/homepage'; } }); .. include:: practices.rst