From 599331501916e26ed4c9a00f66ad386c9803b0ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20PEZ=C3=89?= Date: Mon, 18 May 2026 16:00:06 +0200 Subject: [PATCH] [docs] feat(url-access-token): write documentation for url access token process (#5544) --- docs/deployment/breaking-changes.md | 29 +++++++--- .../2.5.0-url-access-token-enforcement.md | 46 +++++++++++++++ docs/deployment/configuration.md | 34 ++++++----- docs/deployment/url-access-token.md | 58 +++++++++++++++++++ mkdocs.yml | 3 + 5 files changed, 147 insertions(+), 23 deletions(-) create mode 100644 docs/deployment/breaking-changes/2.5.0-url-access-token-enforcement.md create mode 100644 docs/deployment/url-access-token.md diff --git a/docs/deployment/breaking-changes.md b/docs/deployment/breaking-changes.md index 14124dba..d299b9f3 100644 --- a/docs/deployment/breaking-changes.md +++ b/docs/deployment/breaking-changes.md @@ -9,12 +9,13 @@ Please follow the migration guides if you need to upgrade your platform. This table regroups all the breaking changes introduced, with the corresponding version in which the change was implemented. -| Change | Deprecated in | Changed in | -|:------------------------------------------------------------|:--------------|:-----------| -| [OpenCTI / OpenAEV compatibility](#octi-oaev-compatibility) | - | 2.2.0 | -| [OpenAEV encryption of secret](#openaev-encryption) | - | 2.1.0 | -| [OpenAEV renaming](#openaev-renaming) | 1.18.20 | 2.0.0 | -| [OpenAEV CSRF](#openaev-csrf) | - | 2.3.4 | +| Change | Deprecated in | Changed in | +|:--------------------------------------------------------------|:--------------|:-----------| +| [OpenCTI / OpenAEV compatibility](#octi-oaev-compatibility) | - | 2.2.0 | +| [OpenAEV encryption of secret](#openaev-encryption) | - | 2.1.0 | +| [OpenAEV renaming](#openaev-renaming) | 1.18.20 | 2.0.0 | +| [OpenAEV CSRF](#openaev-csrf) | - | 2.3.4 | +| [URL access token enforcement](#url-access-token-enforcement) | - | 2.5.0 | ## OpenAEV 2.2.0 @@ -86,4 +87,18 @@ For more details, see [this migration guide](breaking-changes/2.0.0-openaev-rena Starting with **OpenAEV 2.3.4**, frontend-initiated API calls must include a valid CSRF token. To prevent API authentication and connection issues, make sure all ecosystem components are upgraded to versions compatible with OpenAEV 2.3.4. -For more details, see [this migration guide](breaking-changes/2.3.4-csrf-token-enforcement.md) \ No newline at end of file +For more details, see [this migration guide](breaking-changes/2.3.4-csrf-token-enforcement.md) + +## OpenAEV 2.5.0 + +### Introduction + + + +#### URL access token enforcement for email links + +Starting with **OpenAEV 2.5.0**, OpenAEV no longer accepts legacy email links based on `userId` and `user` query parameters for player access flows. + +OpenAEV now requires token-based links using `GET /api/url/access?token=`, followed by a secure cookie and redirect flow. + +For more details, see [this migration guide](breaking-changes/2.5.0-url-access-token-enforcement.md) \ No newline at end of file diff --git a/docs/deployment/breaking-changes/2.5.0-url-access-token-enforcement.md b/docs/deployment/breaking-changes/2.5.0-url-access-token-enforcement.md new file mode 100644 index 00000000..60609f45 --- /dev/null +++ b/docs/deployment/breaking-changes/2.5.0-url-access-token-enforcement.md @@ -0,0 +1,46 @@ +# URL access token enforcement for email links + +!!! info "" + + * **Introduced in**: `OpenAEV 2.5.0` + +## Description of changes + +Starting with **OpenAEV 2.5.0**, OpenAEV no longer accepts legacy email URLs that rely on `userId` and `user` query parameters for player access flows. + +OpenAEV now requires a short-lived URL access token through: + +```text +/api/url/access?token= +``` + +After the first successful access, OpenAEV sets a secure cookie and redirects the user to the target resource URL. + +## Impact + +Legacy links generated before this change are not compatible with OpenAEV 2.5.0. + +Typical symptoms include: + +- `401 Unauthorized` when opening old email links +- Access failures on player routes that previously relied on legacy query parameters + +## Migration guide + +1. Upgrade OpenAEV to a version that supports URL access token links. +2. Regenerate and resend player emails (Media Pressure, Challenge, and Lessons Learned) so users receive token-based links. +3. Verify your `openaev.base-url` value is correct, because OpenAEV uses it to build email links. +4. Configure token behavior with: + - `openaev.url.access.token.expiry-margin-days` + - `openaev.url.access.token.retention-days` + +!!! warning + Do not keep old links in operational runbooks. Ask users to open newly generated emails after upgrade. + +## Validation checklist after upgrade + +1. Send a new player email and confirm the URL format is `/api/url/access?token=...`. +2. Open the link and verify the redirect succeeds. +3. Confirm the platform sets a secure cookie (`HttpOnly`, `Secure`, `SameSite=Strict`). + + diff --git a/docs/deployment/configuration.md b/docs/deployment/configuration.md index 9b0c68de..e2377fb3 100644 --- a/docs/deployment/configuration.md +++ b/docs/deployment/configuration.md @@ -26,22 +26,24 @@ Here are the configuration keys, for both containers (environment variables) and #### Basic parameters -| Parameter | Environment variable | Default value | Description | -|:-----------------------------------|:-----------------------------------|:----------------------|:-------------------------------------------------------------------------------------------------------------------------| -| server.address | SERVER_ADDRESS | 0.0.0.0 | Listen address of the application | -| server.port | SERVER_PORT | 8080 | Listen port of the application | -| openaev.base-url | OPENAEV_BASE-URL | http://localhost:8080 | Base URL of the application, will be used in some email links | -| server.servlet.session.timeout | SERVER_SERVLET_SESSION_TIMEOUT | 60m | Default duration of session (60 minutes) | -| openaev.cookie-secure | OPENAEV_COOKIE-SECURE | `false` | Turn on if the access is done in HTTPS | -| openaev.cookie-duration | OPENAEV_COOKIE-DURATION | P1D | Cookie duration (default 1 day) | -| openaev.admin.email | OPENAEV_ADMIN_EMAIL | admin@openaev.io | Default login email of the admin user | -| openaev.admin.password | OPENAEV_ADMIN_PASSWORD | ChangeMe | Default password of the admin user | -| openaev.admin.token | OPENAEV_ADMIN_TOKEN | ChangeMe | Default token (must be a valid UUIDv4) | -| openaev.admin.encryption_key | OPENAEV_ADMIN_ENCRYPTION_KEY | ChangeMe | Encryption key used for encrypting sensitive data in database. Encryption key and salt are used to generate a 256bit encryption key for encrypting purpose. | -| openaev.admin.encryption_salt | OPENAEV_ADMIN_ENCRYPTION_SALT | ChangeMe | Encryption salt used for encrypting sensitive data in database. Must be at least 8 bytes long. Encryption key and salt are used to generate a 256bit encryption key for encrypting purpose | -| openaev.healthcheck.key | OPENAEV_HEALTHCHECK_KEY | ChangeMe | The key to use in the health check endpoint (/api/health) | -| inject.execution.threshold.minutes | INJECT_EXECUTION_THRESHOLD_MINUTES | 10 | Inject execution threshold in minutes. If this time is exceeded, the inject will be moved to the MAYBE_PREVENTED status. | -| openaev.starterpack.enabled | OPENAEV_STARTERPACK_ENABLED | true | StarterPack feature, providing default endpoint, asset group, scenarios and dashboards | +| Parameter | Environment variable | Default value | Description | +|:--------------------------------------------|:--------------------------------------------|:----------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| server.address | SERVER_ADDRESS | 0.0.0.0 | Listen address of the application | +| server.port | SERVER_PORT | 8080 | Listen port of the application | +| openaev.base-url | OPENAEV_BASE-URL | http://localhost:8080 | Base URL of the application, will be used in some email links | +| server.servlet.session.timeout | SERVER_SERVLET_SESSION_TIMEOUT | 60m | Default duration of session (60 minutes) | +| openaev.cookie-secure | OPENAEV_COOKIE-SECURE | `false` | Turn on if the access is done in HTTPS | +| openaev.cookie-duration | OPENAEV_COOKIE-DURATION | P1D | Cookie duration (default 1 day) | +| openaev.admin.email | OPENAEV_ADMIN_EMAIL | admin@openaev.io | Default login email of the admin user | +| openaev.admin.password | OPENAEV_ADMIN_PASSWORD | ChangeMe | Default password of the admin user | +| openaev.admin.token | OPENAEV_ADMIN_TOKEN | ChangeMe | Default token (must be a valid UUIDv4) | +| openaev.admin.encryption_key | OPENAEV_ADMIN_ENCRYPTION_KEY | ChangeMe | Encryption key used for encrypting sensitive data in database. Encryption key and salt are used to generate a 256bit encryption key for encrypting purpose. | +| openaev.admin.encryption_salt | OPENAEV_ADMIN_ENCRYPTION_SALT | ChangeMe | Encryption salt used for encrypting sensitive data in database. Must be at least 8 bytes long. Encryption key and salt are used to generate a 256bit encryption key for encrypting purpose | +| openaev.healthcheck.key | OPENAEV_HEALTHCHECK_KEY | ChangeMe | The key to use in the health check endpoint (/api/health) | +| inject.execution.threshold.minutes | INJECT_EXECUTION_THRESHOLD_MINUTES | 10 | Inject execution threshold in minutes. If this time is exceeded, the inject will be moved to the MAYBE_PREVENTED status. | +| openaev.starterpack.enabled | OPENAEV_STARTERPACK_ENABLED | true | StarterPack feature, providing default endpoint, asset group, scenarios and dashboards | +| openaev.url.access.token.expiry-margin-days | OPENAEV_URL_ACCESS_TOKEN_EXPIRY-MARGIN-DAYS | 7 | Number of days added after an exercise end date before URL access tokens expire | +| openaev.url.access.token.retention-days | OPENAEV_URL_ACCESS_TOKEN_RETENTION-DAYS | 30 | Number of days to retain expired or revoked URL access tokens before the purge job deletes them | #### Network and security diff --git a/docs/deployment/url-access-token.md b/docs/deployment/url-access-token.md new file mode 100644 index 00000000..207b7d93 --- /dev/null +++ b/docs/deployment/url-access-token.md @@ -0,0 +1,58 @@ +# URL access token + +This page explains how OpenAEV secures player email links with short-lived URL access tokens. + +## What is this? + +OpenAEV uses URL access tokens to protect links sent in player-facing emails. + +Instead of exposing persistent identifiers in query parameters, OpenAEV now generates an opaque token and sends links in this format: + +```text +/api/url/access?token= +``` + +When a player opens the link, OpenAEV validates the token, sets a secure cookie, and redirects to the target page. + +## Why use it? + +This mechanism reduces the risk of data leakage in browser history, logs, and referrer headers. + +Main security benefits: + +- Token is short-lived and revocable. +- Token is scoped to a user and an exercise. +- OpenAEV stores only a SHA-256 hash in the database. +- OpenAEV removes the token from the URL after first access. + +!!! tip + This change hardens security without changing the player experience. + +## How do I do it? + +### Enable and configure token behavior + +1. Set the token validity margin after the exercise end date. +2. Set the retention window for purge operations. + +| Parameter | Environment variable | Default value | Description | +|:--|:--|:--|:--| +| `openaev.url.access.token.expiry-margin-days` | `OPENAEV_URL_ACCESS_TOKEN_EXPIRY-MARGIN-DAYS` | `7` | Adds a grace period after `exercise.end_date` to compute token expiration. | +| `openaev.url.access.token.retention-days` | `OPENAEV_URL_ACCESS_TOKEN_RETENTION-DAYS` | `30` | Keeps revoked or expired tokens for audit before purge. | + +### Verify email link flow + +1. Send a Media Pressure, Challenge, or Lessons Learned email. +2. Confirm the email contains `/api/url/access?token=...`. +3. Open the link and verify OpenAEV returns a redirect to the target page. +4. Verify the browser receives a cookie with `HttpOnly`, `Secure`, and `SameSite=Strict`. + +## Example + +A player receives this link: + +```text +https:///api/url/access?token= +``` + +OpenAEV validates the token and redirects the player to the initial exercise resource. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 8d75508e..e666e8bd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -118,6 +118,7 @@ nav: - Configuration: deployment/configuration.md - Certificate validation: deployment/certificate-validation.md - Authentication: deployment/authentication.md + - URL access token: deployment/url-access-token.md - Upgrade: deployment/upgrade.md - Ecosystem: - Executors: deployment/ecosystem/executors.md @@ -140,6 +141,8 @@ nav: - OpenAEV renaming: deployment/breaking-changes/2.0.0-openaev-renaming.md - OpenAEV encryption: deployment/breaking-changes/2.1.0-encrypting-password.md - Scenario Generation from OpenCTI Security Coverage: deployment/breaking-changes/2.2.0-opencti-security-coverage.md + - CSRF token enforcement for frontend API calls: deployment/breaking-changes/2.3.4-csrf-token-enforcement.md + - URL access token enforcement for email links: deployment/breaking-changes/2.5.0-url-access-token-enforcement.md - User Guide: - Getting started: usage/getting-started.md - Foundations: