Skip to content

Action server cookie credentials#1784

Merged
dandelany merged 10 commits intodevelopfrom
feat/action-server-cookie-credentials
Feb 25, 2026
Merged

Action server cookie credentials#1784
dandelany merged 10 commits intodevelopfrom
feat/action-server-cookie-credentials

Conversation

@AaronPlave
Copy link
Copy Markdown
Contributor

@AaronPlave AaronPlave commented Feb 20, 2026

  • Tickets addressed: N/A
  • Review: By commit
  • Merge strategy: Merge (no squash)

Description

Adds a configurable cookie forwarding mechanism to the action server, enabling actions to access an env-configured list of browser session cookies (e.g., SSO tokens) for authenticating with external services under the user's identity.

Problem: Actions that need to interact with external services sometimes need user-specific credentials that are separate from the credentials PlanDev authenticates with. These cookies may also be stored as httpOnly which means that the actions server must extract them since the client cannot read them directly. However, these credentials were not being forwarded to the actions server by the client when making a request to /secrets. Additionally, the actions server was not passing any cookies into the action secrets and the action server CORS middleware was configured with Access-Control-Allow-Origin=* which prevented forwarding of cookies.

Approach:

  • The UI sends credentials: 'include' on action server requests when PUBLIC_ACTION_INCLUDE_CREDENTIALS=true (separate aerie-ui PR), causing the browser to include cookies in the request. Implemented in Include credentials when making request to action /secrets plandev-ui#1882.
  • The action server extracts cookies specified by the ACTION_COOKIE_NAMES env var and nests them under a cookies field in the action's secrets (avoiding namespace clashes with built-in secrets like authorization, user, userRole)
  • A new extractCookies utility in utils/auth.ts handles cookie parsing
  • CORS middleware updated with two modes to address a CodeQL security concern about reflecting arbitrary origins with credentials:
    • ACTION_CORS_ALLOWED_ORIGIN set: Uses the configured origin with Access-Control-Allow-Credentials: true, enabling cookie forwarding. This is the secure, recommended configuration.
    • ACTION_CORS_ALLOWED_ORIGIN unset: Reflects the request's Origin header for backward compatibility but does not include Access-Control-Allow-Credentials. Cookies will not be forwarded in this mode.

New environment variables (both optional, no impact if unset):

Container Variable Description
aerie_ui PUBLIC_ACTION_INCLUDE_CREDENTIALS Set to true to include browser credentials (cookies) in action server requests. Default: false.
aerie_action ACTION_COOKIE_NAMES Comma-separated list of browser cookie names to extract and forward to actions as secrets.
aerie_action ACTION_CORS_ALLOWED_ORIGIN Explicit CORS origin. Required for cross-origin cookie forwarding — enables Access-Control-Allow-Credentials: true. If unset, CORS uses * without credentials support (backward-compatible).

Note for cross-origin deployments: For same-origin deployments (UI and action server behind the same reverse proxy), only PUBLIC_ACTION_INCLUDE_CREDENTIALS=true and ACTION_COOKIE_NAMES are needed — CORS headers are not checked by the browser for same-origin requests. For cross-origin deployments, ACTION_CORS_ALLOWED_ORIGIN must also be set to the UI's origin, otherwise the browser will block the response due to missing Access-Control-Allow-Credentials.

Verification

  • Added 3 automated tests for cookie forwarding in tests/app.test.mts:
    • Forwards only configured cookies as secrets (excludes unconfigured ones)
    • No cookies forwarded when ACTION_COOKIE_NAMES is unset
    • Handles cookies with = in values (e.g., base64-encoded tokens)
  • To test manually:
    • External Auth Case
      • Add ACTION_COOKIE_NAMES=test_sso to your .env
      • Add ACTION_CORS_ALLOWED_ORIGIN=localhost to your .env if desired
      • Run UI PR locally with PUBLIC_ACTION_INCLUDE_CREDENTIALS=true in the UI .env
      • Upload an action that prints out secrets for test purposes (see code sample below) and upload it to a workspace in the UI.
      • Open up dev tools in Chrome and under Application -> Cookies, add a new cookie like test_sso = fake_token_123 with domain = localhost, secure = true, and httpOnly = true.
      • Run the new action in the workspace
      • Verify that test_sso appears in logged secrets in the action run results
    • Default Case
      • Unset ACTION_COOKIE_NAMES and ACTION_CORS_ALLOWED_ORIGIN and restart
      • Re-run the same action
      • Verify that test_sso is not present in the action run logs
    • Strict CORS Test
      • Set ACTION_CORS_ALLOWED_ORIGIN=https://google.com and restart
      • Re-run the same action
      • Verify that the browser blocks the secrets request and shows the toast Sending Action Secret Parameters Failed
      • Verify that the action does not run successfully

Test action

function main(actionParameters, actionSettings, actionsAPI) {
  const secrets = actionsAPI.config.SECRETS;

  // Log the secret KEYS (values will be redacted with ***** in logs)
  console.log('Secret keys present: ' + Object.keys(secrets).join(', '));
  
    // Forwarded cookies are nested under secrets.cookies
   const cookies = secrets.cookies || {};
   console.log('Cookie keys present: ' + Object.keys(cookies).join(', '));


  // Return the cookie names and whether they have values
  // (return values are NOT redacted, so we can check actual presence)
  const cookieReport = {};
  for (const key of Object.keys(secrets)) {
    cookieReport[key] = secrets[key] ? `present (${secrets[key].length} chars)` : 'empty';
  }


  return {
    status: "SUCCESS",
    data: cookieReport,
  };
}

exports.main = main;

Documentation

  • Added "PlanDev Action Server" section to deployment/Environment.md documenting all action server env vars
  • Updated .env.template and deployment/.env with commented-out entries for new optional variables
  • Updated all docker-compose files and Kubernetes deployment file
  • Action secrets/credentials docs plandev-docs#10

Future work

N/A

…_ALLOWED_ORIGIN` env is configured to prevent any origin to make credentialed requests.
@duranb duranb added the publish Tells GH to publish docker images for this PR label Feb 23, 2026
Copy link
Copy Markdown
Collaborator

@dandelany dandelany left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good & passes my local testing, thanks @AaronPlave !

I have one comment below, I'm working on a quick change now to implement this, should be ready for re-review shortly.

Copy link
Copy Markdown
Collaborator

@dandelany dandelany left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed an update with a drop-in extractCookies replacement calling cookie library, tests still pass & did another smoke-test locally. GH workflows are being flaky but this is ready to go once they pass.

@dandelany dandelany merged commit fa75908 into develop Feb 25, 2026
24 of 30 checks passed
@dandelany dandelany deleted the feat/action-server-cookie-credentials branch February 25, 2026 19:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

publish Tells GH to publish docker images for this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants