- Public anonymous SDK
- Runtime-signed Hosted Exchange bootstrap
- Customer-issued shared-secret JWE
- Customer-issued public-key JWE with customer-signed payload
Scenario Selection
| Scenario | Browser credential | Customer backend responsibility | Runtime responsibility | When to use |
|---|---|---|---|---|
| Public anonymous SDK | Public SDK API key | None for auth. The app may pass non-sensitive public userContext. | Verifies public key, channel, origin, and issues SDK session tokens. | Anonymous or low-assurance website chat where no PHI or verified customer identity is required. |
| Runtime-signed Hosted Exchange | Short-lived bootstrapToken returned by customer backend | Authenticates the customer, gathers secure attributes, calls Runtime POST /api/v1/sdk/customer-sessions with the channel server secret. | Mints the hosted bootstrap artifact and SDK session token. Applies sdkTokenEnvelopePolicy. | Customers accept a server-to-server Runtime call and want Artemis to own signing/encryption. |
| Customer-issued shared-secret JWE | Short-lived compact JWE returned by customer backend | Authenticates the customer, builds claims, encrypts with the channel JWE shared secret, and returns JWE to the browser. | Decrypts and validates the customer-issued JWE, enforces replay, scope, age, and channel config, then issues SDK session token. | Flow where the customer backend must keep PHI encryption local and avoid the /customer-sessions API call. |
| Customer-issued public-key JWE | Short-lived compact JWE returned by customer backend | Authenticates the customer, signs the payload with the customer private key, encrypts the signed payload with the Runtime channel public key, and returns JWE to the browser. | Decrypts with Runtime private key, verifies customer signature with the configured customer public key, enforces replay, scope, age, and channel config, then issues SDK session token. | Preferred no-API-call flow when security review requires no shared encryption secret on the customer side and explicit issuer authentication. |
- The outer JWE gives confidentiality to Runtime using
RSA-OAEP-256andA256GCM. - The inner JWS gives issuer authentication using the customer signing private key and Runtime-configured customer signing public key.
Shared Runtime Flow After Bootstrap
All four scenarios converge after browser initialization: Important constraints:- The browser SDK config must provide exactly one bootstrap credential:
apiKey,bootstrapToken, orbootstrapTokenProvider. - Public SDK key mode can include
channelId,channelName,deploymentSlug,userContext, andclientSessionIdentifier. - Hosted bootstrap token mode cannot include public-key-only fields such as
apiKey,channelId,channelName,deploymentSlug,userContext, orclientSessionIdentifier. sessionMetadatamay be used with either public-key or Hosted Exchange bootstrap configs. Runtime uses it for SDK init widget display configuration and localization, not as verified identity.- For Hosted Exchange, put verified identity and secure custom attributes in the customer backend token. Do not send PHI or verified identity directly from the browser.
- WebSocket auth should use the one-time
sdk-ticketflow. The legacysdk-authprotocol is compatibility-only for older bundles.
Permission And Origin Resolution
Public API key permissions are stored as coarsechat and voice booleans.
Runtime expands them to SDK permissions:
| Public key permission | Runtime SDK permissions |
|---|---|
chat=true | session:send_message, session:read, attachment:read, attachment:write, attachment:delete |
voice=true | session:voice, session:read |
/api/v1/sdk/customer-sessions request body does not
accept permissions.
Customer-issued JWE payloads may include a narrower permissions array. Runtime
normalizes the requested values, adds session:read for interactive or
attachment grants, intersects the requested set with the channel’s active public
API key permissions, and rejects the token if the effective set is empty.
Allowed customer-issued permission values:
session:send_messagesession:voicesession:readattachment:readattachment:writeattachment:delete
- Public-key SDK init checks the public API key origins and, if present, legacy channel-config origins.
- Hosted Exchange bootstrap init checks both the channel-config origins and the bound public API key origins after the bootstrap token is verified.
- Empty or unset allowed-origin lists behave as unrestricted in code. Production PHI channels should always configure explicit HTTPS origins.
Shared Studio Prerequisites
- Create or select the project that owns the SDK channel.
- Create or select the deployment the SDK channel should route to.
- Create or select a public SDK API key for the project.
- Set allowed origins on the public API key or managed channel key.
- Include the exact browser origins that will host the SDK.
- Do not rely on wildcard origins for production PHI flows.
- Create an SDK channel and bind it to the deployment or environment.
- Keep the channel active only after customer backend and browser changes are deployed.
anonymousfor public anonymous SDK.hosted_exchangefor Runtime-signed, customer-issued shared-secret JWE, and customer-issued public-key JWE.
Shared Deployment Prerequisites
Runtime must have:JWT_SECRET,AUTH_SDK_BOOTSTRAP_SIGNING_SECRET, andAUTH_SDK_SESSION_SIGNING_SECRETconfigured consistently across Runtime pods.ENCRYPTION_MASTER_KEYconfigured when Hosted Exchange token envelope JWE is required or preferred.AUTH_SDK_JWE_ENABLEDunset ortruewhen JWE issuance/verification should be available.REDIS_URLconfigured for distributed SDK session state, WebSocket tickets, replay protection, and rotation locks.- MongoDB available for SDK channel, public key, and customer JWE key metadata.
- HTTPS between browser, customer backend, and Runtime.
jwe_required is configured and capability is not ready, Runtime must fail
closed instead of returning signed Hosted Exchange tokens.
Scenario 1: Public Anonymous SDK
Studio Setup
- Open the project deployment channel settings in Studio.
- Create or edit an SDK channel.
- Set SDK auth mode to
anonymous. - Bind the channel to the target deployment or environment.
- Configure allowed origins for the browser site.
- Save the channel.
- Copy the public SDK API key and channel identifier or channel name.
sdkTokenEnvelopePolicy or customerIssuedJwe on anonymous
channels. Runtime rejects those settings unless auth.mode=hosted_exchange.
Customer Server Changes
No customer server auth endpoint is required. The server that renders the website may provide public configuration values such as:- Runtime endpoint
- Project ID
- Public SDK API key
- Channel ID or channel name
- Deployment slug, when the channel uses deployment-slug selection
Browser SDK Changes
Core SDK:Validation
- Load the browser site from an allowed origin.
- Confirm
/api/v1/sdk/initusesX-Public-Key. - Confirm the request body does not include
bootstrapToken. - Send a chat message.
- Confirm
/api/v1/sdk/ws-ticketsucceeds before WebSocket connect. - Disable the channel or remove the origin and confirm new sessions fail.
Scenario 2: Runtime-Signed Hosted Exchange
This path adds a customer backend endpoint, but lets Runtime mint the bootstrap artifact. The browser never sees the Hosted Exchange channel server secret.Studio Setup
- Open the project deployment channel settings in Studio.
- Create or edit an SDK channel.
- Set SDK auth mode to
hosted_exchange. - Configure allowed origins.
- Select
sdkTokenEnvelopePolicy:signedfor signed-token compatibility.jwe_preferredfor rollout where JWE is used when Runtime capability is ready.jwe_requiredafter the capability endpoint shows Runtime can issue and verify JWE.
- Save the channel.
- Copy the Hosted Exchange server secret when Studio reveals it.
- Store the server secret only in the customer backend secret manager.
Customer Server Changes
Add a backend endpoint that authenticates the customer in the customer’s system, then calls Runtime:- Send exactly one of
channelIdorchannelName. - Do not send
permissions; Runtime derives the effective SDK permissions from the channel’s active public API key. - Keep
customAttributeswithin the SDK user context size limits. Runtime returnsSDK_TOKEN_TOO_LARGEwhen normalized custom attributes exceed the token budget.
channelName variant:
sdkTokenEnvelopePolicy resolves to JWE, tokenEnvelope is "jwe" and
bootstrapToken is a 5-segment compact JWE.
Recommended customer backend controls:
- Authenticate the website user before minting a bootstrap token.
- Collect PHI and secure custom attributes server-side only.
- Keep
verifiedUserIdstable for the customer identity. - Keep the endpoint same-origin or protected by customer auth cookies.
- Do not return the channel server secret to the browser.
- Do not log
bootstrapToken, PHI, or secure custom attributes.
Browser SDK Changes
Use abootstrapTokenProvider so each fresh init gets a new short-lived token:
bootstrapTokenProvider property before appending the custom element.
The widget reads SDK config during its connection/bootstrap lifecycle.
Validation
- Customer backend calls
POST /api/v1/sdk/customer-sessions. - Browser calls
/api/v1/sdk/initwithbootstrapTokenand withoutX-Public-Key. - Runtime returns an SDK session token.
- If
sdkTokenEnvelopePolicy=jwe_required, confirm returned Hosted Exchange bootstrap/session material is JWE or the flow fails closed. - Replay the same bootstrap token and confirm Runtime rejects it.
- Confirm SDK refresh and WebSocket ticket flows succeed.
Scenario 3: Customer-Issued Shared-Secret JWE
This flow requires no new Artemis API call: the customer backend pulls secure data, encrypts the customer bootstrap payload, and the browser passes the compact JWE to the SDK. Shared-secret mode authenticates the issuer by possession of the scoped channel secret and authenticates ciphertext integrity throughA256GCM. It does not use
a separate asymmetric customer signature.
Studio Setup
- Open the SDK channel in Studio.
- Set SDK auth mode to
hosted_exchange. - Enable customer-issued JWE.
- Set key mode to
shared_secret. - Set
maxAgeSecondsbetween60and900. Prefer300. - Choose whether to keep Runtime-issued Hosted Exchange bootstrap enabled:
acceptRuntimeIssued=trueallows the Runtime-signed/customer-sessionsflow to continue during migration.acceptRuntimeIssued=falselimits this channel to customer-issued JWE.
- Save the channel.
- Rotate the customer-issued JWE secret.
- Copy the one-time shared secret and
keyId. - Store the shared secret only in the customer backend secret manager.
Customer Server Changes
Install a JOSE implementation:customAttributes, not secureCustomData.
Customer-issued permission templates:
session:voice on a channel whose
public key has voice=false produces no voice grant. If the intersection is
empty, /api/v1/sdk/init returns a Hosted Exchange permissions error.
Browser SDK Changes
Use the same Hosted Exchange browser configuration as Runtime-signed bootstrap:apiKey, channelId, channelName, deploymentSlug,
userContext, or clientSessionIdentifier in this SDK config.
Validation
- Browser calls the customer backend bootstrap endpoint.
- Customer backend does not call
/api/v1/sdk/customer-sessions. - Browser passes the compact JWE to
/api/v1/sdk/initasbootstrapToken. - Runtime accepts the first use.
- Runtime rejects replay of the same
jti. - Runtime rejects expired tokens and tokens where
exp - iatexceeds channelmaxAgeSeconds. - Runtime rejects tokens with mismatched
tenantId,projectId,channelId,tid,pid, orcid. - Rotate the shared secret and confirm:
- In-flight tokens minted before rotation still work until expiry.
- Newly minted tokens using the old secret fail.
Scenario 4: Customer-Issued Public-Key JWE
This is the preferred no-new-Artemis-API-call option for higher-assurance PHI flows. The customer backend signs the payload, encrypts it to Runtime, and the browser passes only the resulting compact JWE.Key Ownership
| Key material | Owner | Stored where | Purpose |
|---|---|---|---|
| Customer signing private key | Customer | Customer backend secret manager or HSM | Signs the inner JWS. Never leaves the customer environment. |
| Customer signing public key | Customer and Studio/Runtime | Studio channel customerIssuedJwe.customerSigningPublicKey config | Runtime verifies issuer authenticity. |
| Runtime channel private decrypt key | Runtime | Runtime key store / database protected by platform encryption | Decrypts outer JWE. Never leaves Runtime. |
| Runtime channel public encrypt key | Runtime and customer | Studio shows safe key metadata after customer JWE key rotation | Customer encrypts outer JWE for Runtime. |
Studio Setup
- Generate a customer signing key pair in the customer environment.
- Copy only the customer signing public key.
- Open the SDK channel in Studio.
- Set SDK auth mode to
hosted_exchange. - Enable customer-issued JWE.
- Set key mode to
public_key. - Paste the PEM-encoded customer signing public key.
- Set
maxAgeSecondsbetween60and900. Prefer300. - Choose whether
acceptRuntimeIssuedshould remain enabled for migration. - Save the channel.
- Rotate the customer-issued JWE key.
- Copy the Runtime channel public encryption key and
keyId. - Store the Runtime public encryption key and
keyIdin customer backend configuration.
customer-signing-public.pem to Studio. Store
customer-signing-private.pem only in the customer backend secret manager or
HSM. The TypeScript example below expects the private key in PKCS#8 PEM format
and the public key in SPKI PEM format.
Customer-issued public-key JWE config shape:
Customer Server Changes
Install a JOSE implementation:Browser SDK Changes
Use the same Hosted Exchange browser configuration:Validation
- Customer backend does not call
/api/v1/sdk/customer-sessions. - Browser passes compact JWE to
/api/v1/sdk/initasbootstrapToken. - Runtime decrypts the JWE and verifies the inner JWS.
- Runtime rejects an unsigned plaintext payload in public-key mode.
- Runtime rejects wrong
ctyvalues such asapplication/jsonin public-key mode. - Runtime rejects tokens signed by an unconfigured customer private key.
- Runtime rejects replay, scope drift, expired tokens, overlong tokens, and disabled-channel tokens.
- Rotate the Runtime channel public encryption key and confirm:
- In-flight tokens minted before rotation still work until expiry.
- Newly minted tokens using the retired key fail.
Studio Operations Checklist
For public anonymous SDK:- SDK channel auth mode is
anonymous. - Allowed origins include the browser site.
- Public API key is active and scoped to the project.
- Channel is active and bound to the expected deployment/environment.
- SDK channel auth mode is
hosted_exchange. - Server secret exists and is stored by the customer backend.
sdkTokenEnvelopePolicyis selected intentionally.- Runtime capability is ready before selecting
jwe_required. - Customer-issued JWE may remain disabled.
- SDK channel auth mode is
hosted_exchange. customerIssuedJwe.enabled=true.customerIssuedJwe.keyMode=shared_secret.customerIssuedJwe.maxAgeSecondsmatches the customer backend token TTL.- Secret has been rotated and copied once to the customer backend.
acceptRuntimeIssuedmatches the migration plan.
- SDK channel auth mode is
hosted_exchange. customerIssuedJwe.enabled=true.customerIssuedJwe.keyMode=public_key.- Customer signing public key is configured.
- Runtime public encryption key has been rotated and copied to the customer backend.
customerIssuedJwe.maxAgeSecondsmatches the customer backend token TTL.acceptRuntimeIssuedmatches the migration plan.
Studio API Automation Payloads
Use these shapes when automating setup through Studio instead of clicking through the channel configuration UI. Create a Hosted Exchange channel:customerIssuedJweSecret.secret is returned once in the
same response. Store it immediately in the customer backend secret manager. It
will not be available from later safe metadata reads.
Customer Backend Checklist
All Hosted Exchange customer backend endpoints should:- Require the customer application’s own authenticated session.
- Derive
verifiedUserIdserver-side. - Fetch PHI or secure attributes server-side.
- Put secure attributes under
customAttributes. - Generate unique
jtivalues. - Use short TTLs. Prefer 5 minutes or less.
- Avoid logging bootstrap tokens, secure attributes, PHI, server secrets, or private keys.
- Return only
{ "bootstrapToken": "..." }and optional non-sensitive expiry metadata to the browser. - Rate limit token minting per customer session.
- Alert on repeated invalid token minting, Runtime 401s, and replay failures.
| Scenario | Required customer backend material |
|---|---|
| Public anonymous SDK | None for SDK auth. |
| Runtime-signed Hosted Exchange | Hosted Exchange channel server secret. |
| Customer-issued shared-secret JWE | Customer JWE keyId and shared secret. |
| Customer-issued public-key JWE | Customer signing private key, Runtime channel public encryption key, and customer JWE keyId. |
Browser SDK Checklist
For public anonymous SDK:- Use
apiKey. - Optional:
channelId,channelName,deploymentSlug,userContext,clientSessionIdentifier.
- Use
bootstrapTokenProviderwhen possible. - Do not combine Hosted Exchange bootstrap config with
apiKey. - Do not pass browser
userContext; put verified data in the backend token. - Do not pass
channelId,channelName, ordeploymentSlug; Runtime resolves those from the bootstrap token. projectIdis still required for bootstrap-token configs.sessionMetadatais allowed, but it is not identity. Use it for safe browser context such as locale, timezone, or UI context.- Make the bootstrap provider call same-origin or protected by customer auth.
- Handle bootstrap failure as an auth/session startup failure, not as a bot error.
Manual Runtime Probes
Use these probes after Studio and customer backend setup. Replace placeholders with environment-specific values and do not paste real secrets into tickets, logs, or shared terminals. Public anonymous SDK init:| Probe | Expected result |
|---|---|
Send both X-Public-Key and bootstrapToken to /api/v1/sdk/init. | 400 INVALID_BOOTSTRAP_REQUEST |
Send a Hosted Exchange bootstrap token with channelId in the init body. | 400 INVALID_BOOTSTRAP_REQUEST |
Send customer bootstrap token with browser userContext. | 400 INVALID_BOOTSTRAP_REQUEST |
| Replay the same customer bootstrap token. | 401 Bootstrap token already used or invalid/expired token response |
| Use an origin outside the channel/public key allowlist. | 403 Origin not allowed |
Use public-key customer JWE with cty=application/json. | 401 Invalid or expired bootstrap token |
Use shared-secret customer JWE with cty=application/jose. | 401 Invalid or expired bootstrap token |
Deployment Checklist
Runtime:- Configure
JWT_SECRET. - Configure
AUTH_SDK_BOOTSTRAP_SIGNING_SECRET. - Configure
AUTH_SDK_SESSION_SIGNING_SECRET. - Configure
ENCRYPTION_MASTER_KEYfor JWE envelope support. - Keep
AUTH_SDK_JWE_ENABLEDunset ortruefor JWE rollout. - Configure
REDIS_URLfor tickets, replay protection, and distributed state. - Expose Runtime over HTTPS.
- Verify
/api/projects/:projectId/sdk-jwe-capabilitybefore enforcing JWE. - Deploy all Runtime pods with the same auth and encryption settings.
- Studio must reach Runtime for channel mutation APIs and JWE capability preflight.
- Studio users need channel permissions to create/update SDK channel auth settings.
- Treat one-time revealed secrets as unrecoverable; rotate if they are missed or exposed.
- Store Runtime endpoint, tenant ID, project ID, and channel ID as deploy config.
- Store scenario-specific secrets in a secret manager or HSM.
- Rotate secrets through Studio first, then update customer backend config.
- Deploy customer backend before switching the browser SDK to Hosted Exchange bootstrap.
- Use HTTPS and secure cookies for the browser-to-customer bootstrap endpoint.
- Serve an SDK bundle version that supports
bootstrapTokenProviderand WebSocketsdk-ticket. - Set Runtime endpoint and project ID per environment.
- Keep Hosted Exchange bootstrap calls credentialed when the customer session uses cookies.
- Do not persist bootstrap tokens in local storage.
End-To-End Cutover Plan
- Create or update the SDK channel in Studio.
- Set allowed origins and deployment binding.
- For Hosted Exchange, configure channel auth mode and token/JWE settings.
- Deploy Runtime with required auth, Redis, and encryption configuration.
- Verify Runtime JWE capability if
jwe_preferredorjwe_requiredis used. - Deploy the customer backend bootstrap endpoint.
- Validate the backend endpoint with a real customer session.
- Deploy browser SDK changes.
- Start with an internal or allowlisted origin.
- Exercise init, refresh, chat send, attachment if used, WebSocket ticket, and WebSocket connect.
- Check Runtime logs and audit events for invalid token, replay, origin, or scope failures.
- For migration channels, keep
acceptRuntimeIssued=trueuntil all browser and customer backend clients are using customer-issued JWE. - When ready, set
acceptRuntimeIssued=falsefor customer-issued-only channels, or setsdkTokenEnvelopePolicy=jwe_requiredfor Runtime-issued Hosted Exchange channels.
Expanded Scenario Coverage Matrix
Use this matrix for implementation review, QA planning, and customer security approval. A complete rollout should cover the positive path and at least the listed negative path for each scenario in the target environment.| Scenario | Positive path | Negative/security path | Layers covered |
|---|---|---|---|
| Public anonymous chat | Browser initializes with apiKey, channelId or channelName, sends chat, mints WebSocket ticket, connects with sdk-ticket. | Remove origin from allowed origins or disable public API key and confirm new init fails. | Studio, public API key, Runtime init, SDK, WebSocket ticket |
| Public anonymous voice | Public API key has voice=true; browser initializes and starts voice flow. | Set voice=false or disable voice widget capability and confirm voice permission is absent or voice flow is denied. | Studio key permissions, Runtime permissions, SDK voice |
| Public anonymous attachment | Public API key has chat=true; chat flow uploads/uses attachment where product flow allows it. | Request attachment behavior when chat permission is disabled and confirm attachment permissions are not granted. | Public key permissions, SDK HTTP routes, Runtime auth |
| Runtime-signed Hosted Exchange signed | Customer backend calls /customer-sessions; browser exchanges returned token through /sdk/init; refresh and ws-ticket succeed. | Send wrong X-SDK-Channel-Secret or omit both channelId and channelName; Runtime rejects. | Customer backend, Runtime /customer-sessions, Runtime init, SDK |
| Runtime-signed Hosted Exchange JWE preferred | Channel uses sdkTokenEnvelopePolicy=jwe_preferred; capability ready returns tokenEnvelope=jwe. | Test capability-unready lower environment and confirm policy degrades only when configured as preferred. | Studio policy, Runtime JWE capability, token envelope |
| Runtime-signed Hosted Exchange JWE required | Channel uses sdkTokenEnvelopePolicy=jwe_required; capability ready returns JWE bootstrap/session tokens. | Capability unavailable fails closed with SDK_JWE_UNAVAILABLE; signed token should not be accepted. | Deployment config, Runtime capability, token envelope policy |
| Customer-issued shared-secret JWE | Customer backend encrypts JSON payload with alg=dir, enc=A256GCM, cty=application/json; Runtime accepts first use. | Wrong shared secret, wrong cty, replayed jti, expired token, or scope mismatch all fail. | Studio customer JWE config, customer backend JOSE, Runtime verifier, SDK |
| Customer-issued public-key JWE | Customer backend signs inner JWS with customer private key, encrypts outer JWE to Runtime public key, and Runtime verifies signature. | Unsigned payload, wrong customer signing key, wrong cty, wrong kid, or stale Runtime public key fails. | Customer signing keys, Runtime encryption key, Studio config, Runtime verifier |
| Customer-issued migration | acceptRuntimeIssued=true allows both Runtime-signed and customer-issued bootstrap during rollout. | Set acceptRuntimeIssued=false and confirm Runtime-issued /customer-sessions tokens no longer bootstrap that channel. | Studio config, migration controls, Runtime bootstrap resolver |
| Key rotation | Rotate Hosted Exchange server secret or customer JWE material and update customer backend configuration. | Tokens minted before rotation work only until normal expiry; newly minted tokens with retired material fail. | Studio rotation, secret management, Runtime key store |
| Permissions narrowing | Customer-issued token requests a subset such as read-only or voice-only. Runtime intersects with public key permissions. | Request permissions not allowed by the public key and confirm denied or narrowed effective permissions. | Customer backend claims, public key permissions, Runtime permissions |
| Session metadata | Browser sends safe sessionMetadata such as locale/timezone and widget text resolves as expected. | Oversized sessionMetadata fails validation; secrets in metadata are not persisted durably by design. | SDK, Runtime schemas, widget config/localization |
- Studio screenshot or API response showing channel auth mode, token envelope policy, customer JWE mode, and active key metadata.
- Customer backend request/response trace with secrets and PHI redacted.
- Runtime init response showing
channelId,permissions,tokenEnvelopewhen present, andexpiresIn. - SDK browser trace showing no channel secret, customer JWE secret, Runtime private key, or customer signing private key is present client-side.
- WebSocket ticket response and successful WebSocket connection using
sdk-ticket. - Negative-path evidence for replay, origin, expiry, and key-mode mismatch for customer-issued JWE scenarios.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
SDK config must provide exactly one bootstrap credential | Browser config includes both apiKey and bootstrapToken or neither. | Use apiKey for public anonymous, or bootstrapTokenProvider for Hosted Exchange. |
| Runtime rejects bootstrap with public-key-only fields | Hosted Exchange SDK config includes channelId, channelName, deploymentSlug, userContext, or clientSessionIdentifier. | Remove those fields from Hosted Exchange browser config. |
config.customerIssuedJwe requires auth.mode=hosted_exchange | Customer-issued JWE was configured on an anonymous channel. | Switch channel auth mode to Hosted Exchange first. |
customerSigningPublicKey is required when keyMode=public_key | Public-key mode enabled without the customer signing public key. | Generate customer signing keys and paste the PEM public key in Studio. |
customer_issued_jwe_content_type_mismatch | Shared-secret/public-key mode used the wrong outer cty. | Use application/json for shared secret and application/jose for public key. |
customer_issued_jwe_key_mode_mismatch | Channel key mode changed but customer backend still uses old key material. | Rotate key material for the active mode and update customer backend config. |
| Replay failures | Customer backend reused a jti or browser retried a static bootstrap token. | Generate a fresh token for every init and prefer bootstrapTokenProvider. |
| Expired or overlong token failures | exp, iat, or TTL exceeds channel maxAgeSeconds. | Keep clocks in sync and use TTL at or below the channel setting. |
| CORS failure | Browser origin not allowed for the channel/public API key. | Add exact HTTPS origin in Studio. |
| WebSocket fails after init succeeds | Browser bundle is old or Redis/ticket store is unavailable. | Use SDK with sdk-ticket support and verify Redis Runtime config. |
jwe_required fails closed | Runtime JWE capability is unavailable. | Verify ENCRYPTION_MASTER_KEY, AUTH_SDK_JWE_ENABLED, and capability route readiness. |
Security Review Notes
- Public anonymous SDK is not a PHI flow. Treat any browser-provided
userContextas unverified. - Runtime-signed Hosted Exchange sends secure attributes to Runtime during
/api/v1/sdk/customer-sessions. Use it only when that server-to-server API call is approved. - Customer-issued shared-secret JWE avoids the Runtime minting API call but uses shared scoped secret material on both sides.
- Customer-issued public-key JWE avoids the Runtime minting API call, avoids a shared encryption secret on the customer side, and provides explicit issuer authentication through the inner JWS.
- In all Hosted Exchange modes, Runtime still issues the canonical SDK session token after bootstrap. The customer-issued token is bootstrap-only.
- Do not store PHI in logs, URLs, local storage, WebSocket protocols, or analytics metadata.