JWT authentication
JWT authentication ties every agent request to a backend-verified user identity. Use it on any production deployment so a user can only access their own conversations, history, and actions, and so requests can’t be forged from the client.
Why use JWT
Section titled “Why use JWT”Without authentication, a malicious actor could impersonate a user, read private conversations, or invoke actions on their behalf. JWT authentication guarantees:
- A user can only access their own conversations and data.
- Requests to the agent can’t be forged from the client side.
- Conversation history and agent actions are protected from identity theft.
What is a JWT?
Section titled “What is a JWT?”A JSON Web Token (JWT) is a compact, signed token used to transmit identity information between systems. A JWT:
- Is generated by a trusted backend.
- Is cryptographically signed with a secret key.
- Can be verified by a server without additional database lookups.
- Has a built-in expiration time.
In Foldspace, the JWT acts as proof of identity for the user interacting with the agent. Requiring a server-signed token means user identity can’t be spoofed, only authenticated users can send messages or retrieve conversations, and tokens expire automatically to limit exposure if compromised.
How it works
Section titled “How it works”- You generate a secret key in the Foldspace dashboard.
- Your backend uses the secret to sign a JWT with HS256.
- The signed JWT is sent to the browser.
- The Foldspace Web SDK includes the JWT in every request.
- Foldspace verifies the token and user identity on every call.
sequenceDiagram participant B as Your Backend participant C as Browser participant S as Foldspace SDK participant F as Foldspace B->>B: Sign JWT (HS256) with secret key B->>C: Return signed JWT C->>S: Initialize with token S->>F: Request + JWT header F->>F: Verify signature & expiry F-->>S: Authenticated response Note over S,F: On expiry, SDK calls onTokenExpired S->>C: Request fresh token C->>B: Fetch new JWT B->>C: New signed JWT C->>S: Return token
Step 1: Generate a secret key
Section titled “Step 1: Generate a secret key”JWT signing keys are managed under Settings → Identity Verification. You can generate one or more JWT secret keys.
- These keys sign JWTs in your backend.
- They must be kept private and secure.
- They must never be exposed in frontend code.
Once generated, copy the secret key and store it securely, for example, as an environment variable.
Access control
Section titled “Access control”To copy a secret key or change a key’s status, a Foldspace user must have the Jwt Settings Admin role. Users without this role can view configuration but can’t access or modify secret keys.
Rotate keys
Section titled “Rotate keys”Foldspace supports key rotation so you can maintain security without service disruption. You manage rotation, and multiple secret keys can coexist for safe transitions in production.
Each secret key has a status that controls how it’s enforced.
Secret key statuses
Section titled “Secret key statuses”| Status | Enforcement | Notes |
|---|---|---|
INACTIVE | Not enforced | Default status when a key is created. The key can be copied and safely prepared for deployment. Can be moved to INACTIVE from any status except REVOKED. |
ACTIVE | Fully enforced | Tokens signed with this key are accepted by Foldspace. |
TESTING | Evaluated, not enforced | Validates JWT signing without enforcing authentication. Only one TESTING key is allowed at a time. Verification results are returned in a response header. Does not affect production traffic or agent availability. |
DEPRECATED | Valid and enforced | Used during key rotation. Lets existing backend deployments keep working while a new key is rolled out. |
REVOKED | Rejected | Permanently disabled and deleted. Tokens signed with this key are rejected. Status can’t be changed once revoked. |
Recommended rotation flow
Section titled “Recommended rotation flow”- Create a new secret key (initially
INACTIVE). - Deploy the new key to your backend.
- Move the new key to
ACTIVE. - Move the old key to
DEPRECATED. - Once fully migrated, move the deprecated key to
REVOKED.
This rotates keys with no downtime.
stateDiagram-v2 [*] --> INACTIVE: Key created INACTIVE --> ACTIVE: Deploy & activate INACTIVE --> TESTING: Validate first TESTING --> ACTIVE: Promote ACTIVE --> DEPRECATED: New key activated DEPRECATED --> REVOKED: Migration complete REVOKED --> [*] note right of TESTING: One TESTING key at a time.<br/>Not enforced — result in header. note right of DEPRECATED: Still accepted.<br/>Gives backends time to migrate.
Step 2: Sign the JWT in your backend
Section titled “Step 2: Sign the JWT in your backend”Create the JWT only in your backend and sign it with the HS256 algorithm. Tokens signed with any other algorithm are rejected.
Required payload
Section titled “Required payload”{ "userId": "<the same user ID you pass to the Foldspace JS SDK>", "exp": <expiration time in seconds since epoch>}Signing requirements
Section titled “Signing requirements”| Requirement | Value |
|---|---|
| Algorithm | HS256 |
| Secret | ACTIVE or DEPRECATED Foldspace secret key |
| Location | Backend only |
Code examples
Section titled “Code examples”import jwt from "jsonwebtoken";
const FOLDSPACE_SECRET = process.env.FOLDSPACE_JWT_SECRET;
function generateFoldspaceToken(userId) { const expiresInSeconds = Math.floor(Date.now() / 1000) + (15 * 60);
return jwt.sign( { userId, exp: expiresInSeconds }, FOLDSPACE_SECRET, { algorithm: "HS256" } );}import jwtimport timeimport os
FOLDSPACE_SECRET = os.environ["FOLDSPACE_JWT_SECRET"]
def generate_foldspace_token(user_id): payload = { "userId": user_id, "exp": int(time.time()) + 900 }
return jwt.encode( payload, FOLDSPACE_SECRET, algorithm="HS256" )require 'jwt'
secret = ENV['FOLDSPACE_JWT_SECRET']
def generate_foldspace_token(user_id, secret) payload = { userId: user_id, exp: Time.now.to_i + 900 }
JWT.encode(payload, secret, 'HS256')endStep 3: Pass the JWT to the Web SDK
Section titled “Step 3: Pass the JWT to the Web SDK”Provide the signed JWT to the Foldspace Web SDK through the agent API:
// 1. Fetch the token from your backend APIconst response = await fetch('/api/auth/foldspace-token');const { token } = await response.json();
// 2. Initialize Foldspace agent via the agent APIconst agent = foldspace.agent({ apiName: 'the-agent-api-name', token: token, onTokenExpired: async () => { const response = await fetch('/api/auth/foldspace-token'); const { token } = await response.json(); console.log('token refreshed', token); return token; }});
agent.show();Here, the frontend fetches a signed JWT from your backend and passes it via the token property. The SDK attaches the token to every request. When the token expires, the SDK calls onTokenExpired, and your UI fetches and returns a new token.
Test your signed JWT
Section titled “Test your signed JWT”Use a TESTING key to validate JWT signing before you enforce authentication in production.
- Move a secret key to
TESTING(only one key can be inTESTINGat a time). - Sign a JWT with the
TESTINGkey. - Send requests using that JWT via the Foldspace SDK.
- Foldspace evaluates the token and returns the result in a response header.
Response header
Section titled “Response header”For requests signed with a TESTING key, Foldspace returns the verification result in this header:
X-Jwt-Testing-Result| Value | Meaning |
|---|---|
validated | The JWT is correctly signed and structured. |
failed | The JWT is invalid, expired, or incorrectly signed. |
This lets you verify signature correctness, payload structure, and expiration handling without impacting production users.
Use a TESTING key when you want to validate a new backend JWT implementation, confirm the signing algorithm (HS256), verify payload structure and expiration handling, or test new keys before promoting them to ACTIVE.
Choose a secure expiration time
Section titled “Choose a secure expiration time”- Use short-lived tokens (5–30 minutes).
- Refresh tokens from your backend when needed.
Short expiration times reduce risk and align with modern security standards.
Error handling and token lifecycle
Section titled “Error handling and token lifecycle”Token expired. The SDK invokes onTokenExpired. Fetch a new JWT with a fresh exp from your backend and return it to the SDK.
Invalid token. If the token is invalid or can’t be verified, all agent requests are rejected, the agent is automatically hidden from the UI, and user data and actions remain protected.
Related
Section titled “Related”- HMAC Identity Verification: verify identify calls server-side with HMAC-SHA256.
- Authentication: API keys and scopes.