Sessions
Sessions let you track user behavior and manage authentication across your products using JWT-based tokens.
Frontend clients (publishable key)
When using @ductape/client, @ductape/react, or @ductape/vue with a publishable key (frontend/BFF flow):
- Session in params: Every request (e.g.
storage.upload,databases.query,actions.run) must include asessionproperty in the options object. The value is a session token issued by your backend. The proxy rejects requests that omitsessionor pass an empty value. - Session APIs are backend-only: The client SDKs do not allow calling session methods (
start,verify,refresh,revoke,revokeAll,listActive,getInfo,enableAutoRefresh) when using a publishable key—those methods throw. Sessions must be started, verified, and revoked only on the backend. Your backend returns a session token to the frontend (e.g. after login); the frontend then passes that token assessionin each Ductape request.
See Frontend access key strategies for the full security model.
Quick Example
Use the sessions API on the Ductape instance. Initialize with your access key:
- TypeScript
- Java
- Go
- .NET
import Ductape from '@ductape/sdk';
const ductape = new Ductape({
accessKey: 'your-access-key',
});
// Start a session (creates tokens)
const result = await ductape.sessions.start({
tag: 'user-session',
data: { userId: '123', email: 'user@example.com' },
});
console.log(result.token); // JWT token (format: tag:jwt)
console.log(result.refreshToken); // Refresh token
console.log(result.sessionId); // Session ID
console.log(result.expiresAt); // Expiration date
import app.ductape.sdk.Ductape;
import app.ductape.sdk.core.EnvType;
import app.ductape.sdk.core.RequestContext;
RequestContext auth = new RequestContext(null, null, null, null, 'your-access-key');
Ductape ductape = new Ductape(EnvType.PRODUCTION, auth);
// Start a session (creates tokens)
Map<String, Object> result = ductape.sessions.start(Map.of(
"tag", "user-session",
data: Map.of( "userId", "123", "email", "user@example.com" )
));
System.out.println(result.token); // JWT token (format: tag:jwt)
System.out.println(result.refreshToken); // Refresh token
System.out.println(result.sessionId); // Session ID
System.out.println(result.expiresAt); // Expiration date
import (
"context"
"github.com/ductape/ductape/sdk/go/core"
ductapesdk "github.com/ductape/ductape/sdk/go/ductape"
)
auth := core.NewRequestContext("", "", "", "", 'your-access-key')
client, err := ductapesdk.New(core.EnvProduction, auth)
if err != nil {
return err
}
// Start a session (creates tokens)
result := client.sessions.start({
"tag": "user-session",
data: { "userId": "123", "email": "user@example.com" },
});
fmt.Println(result.token); // JWT token (format: tag:jwt)
fmt.Println(result.refreshToken); // Refresh token
fmt.Println(result.sessionId); // Session ID
fmt.Println(result.expiresAt); // Expiration date
using Ductape.Sdk;
using Ductape.Sdk.Core;
var auth = new RequestContext(null, null, null, null, 'your-access-key', null);
var ductape = new Ductape(EnvType.Production, auth);
// Start a session (creates tokens)
var result = await ductape.sessions.start({
["tag"] = "user-session",
data: { ["userId"] = "123", ["email"] = "user@example.com" },
});
Console.WriteLine(result.token); // JWT token (format: tag:jwt)
Console.WriteLine(result.refreshToken); // Refresh token
Console.WriteLine(result.sessionId); // Session ID
Console.WriteLine(result.expiresAt); // Expiration date
Starting a Session
Start a new session to get tokens. The session tag must match a session configuration you created for the product.
- TypeScript
- Java
- Go
- .NET
const result = await ductape.sessions.start({
tag: 'user-session',
data: {
userId: 'user_123',
email: 'john@example.com',
role: 'admin',
},
});
// Returns
// { token: 'tag:eyJhbGciOi...', refreshToken: '...', expiresAt?: Date, sessionId?: string }
Map<String, Object> result = ductape.sessions.start(Map.of(
"tag", "user-session",
data: Map.of(
"userId", "user_123",
"email", "john@example.com",
"role", "admin"
)
));
// Returns
// Map.of( "token", "tag:eyJhbGciOi...", "refreshToken", "...", expiresAt?: Date, sessionId?: string )
result := client.sessions.start({
"tag": "user-session",
data: {
"userId": "user_123",
"email": "john@example.com",
"role": "admin",
},
});
// Returns
// { "token": "tag:eyJhbGciOi...", "refreshToken": "...", expiresAt?: Date, sessionId?: string }
var result = await ductape.sessions.start({
["tag"] = "user-session",
data: {
["userId"] = "user_123",
["email"] = "john@example.com",
["role"] = "admin",
},
});
// Returns
// { ["token"] = "tag:eyJhbGciOi...", ["refreshToken"] = "...", expiresAt?: Date, sessionId?: string }
Verifying a Session
Verify a session token and read the stored data:
- TypeScript
- Java
- Go
- .NET
const verifyResult = await ductape.sessions.verify({
tag: 'user-session',
token: result.token, // or 'tag:jwt' string
});
if (verifyResult.valid) {
console.log('User data:', verifyResult.data);
console.log('Session ID:', verifyResult.sessionId);
console.log('Expires at:', verifyResult.expiresAt);
} else {
console.log('Invalid or expired token');
}
Map<String, Object> verifyResult = ductape.sessions.verify(Map.of(
"tag", "user-session",
token: result.token, // or 'tag:jwt' string
));
if (verifyResult.valid) Map.of(
System.out.println('User "data", ", verifyResult.data);
System.out.println("Session "ID", ", verifyResult.sessionId);
System.out.println("Expires "at", ", verifyResult.expiresAt);
) else Map.of(
System.out.println("Invalid or expired token');
)
verifyResult := client.sessions.verify({
"tag": "user-session",
token: result.token, // or 'tag:jwt' string
});
if (verifyResult.valid) {
fmt.Println('User "data": ", verifyResult.data);
fmt.Println("Session "ID": ", verifyResult.sessionId);
fmt.Println("Expires "at": ", verifyResult.expiresAt);
} else {
fmt.Println("Invalid or expired token');
}
var verifyResult = await ductape.sessions.verify({
["tag"] = "user-session",
token: result.token, // or 'tag:jwt' string
});
if (verifyResult.valid) {
Console.WriteLine('User ["data"] = ", verifyResult.data);
Console.WriteLine("Session ["ID"] = ", verifyResult.sessionId);
Console.WriteLine("Expires ["at"] = ", verifyResult.expiresAt);
} else {
Console.WriteLine("Invalid or expired token');
}
Refreshing a Session
Renew an expired session using the refresh token:
- TypeScript
- Java
- Go
- .NET
const refreshResult = await ductape.sessions.refresh({
tag: 'user-session',
refreshToken: result.refreshToken,
});
// Returns new tokens (same shape as start)
console.log(refreshResult.token);
console.log(refreshResult.refreshToken);
console.log(refreshResult.sessionId);
Map<String, Object> refreshResult = ductape.sessions.refresh(Map.of(
"tag", "user-session",
refreshToken: result.refreshToken
));
// Returns new tokens (same shape as start)
System.out.println(refreshResult.token);
System.out.println(refreshResult.refreshToken);
System.out.println(refreshResult.sessionId);
refreshResult := client.sessions.refresh({
"tag": "user-session",
refreshToken: result.refreshToken,
});
// Returns new tokens (same shape as start)
fmt.Println(refreshResult.token);
fmt.Println(refreshResult.refreshToken);
fmt.Println(refreshResult.sessionId);
var refreshResult = await ductape.sessions.refresh({
["tag"] = "user-session",
refreshToken: result.refreshToken,
});
// Returns new tokens (same shape as start)
Console.WriteLine(refreshResult.token);
Console.WriteLine(refreshResult.refreshToken);
Console.WriteLine(refreshResult.sessionId);
Revoking a Session
Invalidate a session by session ID or user identifier:
- TypeScript
- Java
- Go
- .NET
// Revoke by session ID
await ductape.sessions.revoke({
tag: 'user-session',
sessionId: 'session-uuid',
});
// Or revoke by user identifier (from session selector)
await ductape.sessions.revoke({
tag: 'user-session',
identifier: 'user_123',
});
// Revoke by session ID
ductape.sessions.revoke(Map.of(
"tag", "user-session",
"sessionId", "session-uuid"
));
// Or revoke by user identifier (from session selector)
ductape.sessions.revoke(Map.of(
"tag", "user-session",
"identifier", "user_123"
));
// Revoke by session ID
client.sessions.revoke({
"tag": "user-session",
"sessionId": "session-uuid",
});
// Or revoke by user identifier (from session selector)
client.sessions.revoke({
"tag": "user-session",
"identifier": "user_123",
});
// Revoke by session ID
await ductape.sessions.revoke({
["tag"] = "user-session",
["sessionId"] = "session-uuid",
});
// Or revoke by user identifier (from session selector)
await ductape.sessions.revoke({
["tag"] = "user-session",
["identifier"] = "user_123",
});
Listing Active Sessions
Get a paginated list of active (runtime) sessions:
- TypeScript
- Java
- Go
- .NET
const result = await ductape.sessions.listActive({
tag: 'user-session',
identifier: 'user_123', // Optional: filter by user
page: 1,
limit: 10,
});
console.log('Total:', result.total);
for (const session of result.sessions) {
console.log('Session ID:', session.sessionId);
console.log('Started at:', session.startAt);
console.log('Expires at:', session.endAt);
console.log('Active:', session.active);
}
Map<String, Object> result = ductape.sessions.listActive(Map.of(
"tag", "user-session",
"identifier", "user_123", // Optional: filter by user
"page", 1,
"limit", 10
));
System.out.println('"Total", ", result.total);
for (Map<String, Object> session of result.sessions) Map.of(
System.out.println("Session "ID", ", session.sessionId);
System.out.println("Started "at", ", session.startAt);
System.out.println("Expires "at", ", session.endAt);
System.out.println("Active:', session.active);
)
result := client.sessions.listActive({
"tag": "user-session",
"identifier": "user_123", // Optional: filter by user
"page": 1,
"limit": 10,
});
fmt.Println('"Total": ", result.total);
for (const session of result.sessions) {
fmt.Println("Session "ID": ", session.sessionId);
fmt.Println("Started "at": ", session.startAt);
fmt.Println("Expires "at": ", session.endAt);
fmt.Println("Active:', session.active);
}
var result = await ductape.sessions.listActive({
["tag"] = "user-session",
["identifier"] = "user_123", // Optional: filter by user
["page"] = 1,
["limit"] = 10,
});
Console.WriteLine('["Total"] = ", result.total);
for (var session of result.sessions) {
Console.WriteLine("Session ["ID"] = ", session.sessionId);
Console.WriteLine("Started ["at"] = ", session.startAt);
Console.WriteLine("Expires ["at"] = ", session.endAt);
Console.WriteLine("Active:', session.active);
}
Creating Session Configurations
Define what data a session holds and how long it lasts. This is product-level config, not starting a session. Use sessions.create(product, payload):
- TypeScript
- Java
- Go
- .NET
await ductape.sessions.create('my-product', {
name: 'Checkout Session',
tag: 'checkout-session',
description: 'Session for checkout flow',
selector: '$Session{userId}', // must be "$Session{fieldName}" — plain "userId" is rejected
expiry: 1,
period: 'hours',
schema: {
// Sample data — actual example values, NOT type declarations
// The value at the selector path must be a primitive (string/number/boolean)
userId: 'user_123',
email: 'user@example.com',
cartId: 'cart_456',
},
});
ductape.sessions.create('my-product', Map.of(
"name", "Checkout Session",
"tag", "checkout-session",
"description", "Session for checkout flow",
"selector", "$SessionMap.of(userId)", // must be "$SessionMap.of(fieldName)" — plain "userId" is rejected
"expiry", 1,
"period", "hours",
schema: Map.of(
// Sample data — actual example values, NOT type declarations
// The value at the selector path must be a primitive (string/number/boolean)
"userId", "user_123",
"email", "user@example.com",
"cartId", "cart_456"
)
));
client.sessions.create('my-product', {
"name": "Checkout Session",
"tag": "checkout-session",
"description": "Session for checkout flow",
"selector": "$Session{userId}", // must be "$Session{fieldName}" — plain "userId" is rejected
"expiry": 1,
"period": "hours",
schema: {
// Sample data — actual example values, NOT type declarations
// The value at the selector path must be a primitive (string/number/boolean)
"userId": "user_123",
"email": "user@example.com",
"cartId": "cart_456",
},
});
await ductape.sessions.create('my-product', {
["name"] = "Checkout Session",
["tag"] = "checkout-session",
["description"] = "Session for checkout flow",
["selector"] = "$Session{userId}", // must be "$Session{fieldName}" — plain "userId" is rejected
["expiry"] = 1,
["period"] = "hours",
schema: {
// Sample data — actual example values, NOT type declarations
// The value at the selector path must be a primitive (string/number/boolean)
["userId"] = "user_123",
["email"] = "user@example.com",
["cartId"] = "cart_456",
},
});
Session config fields
| Field | Type | Description |
|---|---|---|
name | string | Display name |
tag | string | Unique identifier (used in start/verify/refresh) |
description | string | Purpose of the session |
selector | string | Primary identifier path in $Session{fieldName} format (e.g. '$Session{userId}'). The field at this path in schema must be a primitive. Used as the lookup key for revoke, list, and analytics. |
expiry | number | Duration before expiration |
period | string | Time unit: seconds, minutes, hours, days |
schema | object | Sample data showing example values that will be embedded in the JWT. Each field must have a primitive value at the selector path. Actual runtime values are passed via sessions.start. |
Listing and fetching session configs
- TypeScript
- Java
- Go
- .NET
// List all session configs for a product
const configs = await ductape.sessions.list('my-product');
// Fetch one by tag
const config = await ductape.sessions.fetch('my-product', 'user-session');
// Update
await ductape.sessions.update('my-product', 'user-session', { expiry: 2, period: 'hours' });
// Delete
await ductape.sessions.delete('my-product', 'user-session');
// List all session configs for a product
Map<String, Object> configs = ductape.sessions.list('my-product');
// Fetch one by tag
Map<String, Object> config = ductape.sessions.fetch('my-product', 'user-session');
// Update
ductape.sessions.update('my-product', 'user-session', Map.of( "expiry", 2, "period", "hours" ));
// Delete
ductape.sessions.delete('my-product', 'user-session');
// List all session configs for a product
configs := client.sessions.list('my-product');
// Fetch one by tag
config := client.sessions.fetch('my-product', 'user-session');
// Update
client.sessions.update('my-product', 'user-session', { "expiry": 2, "period": "hours" });
// Delete
client.sessions.delete('my-product', 'user-session');
// List all session configs for a product
var configs = await ductape.sessions.list('my-product');
// Fetch one by tag
var config = await ductape.sessions.fetch('my-product', 'user-session');
// Update
await ductape.sessions.update('my-product', 'user-session', { ["expiry"] = 2, ["period"] = "hours" });
// Delete
await ductape.sessions.delete('my-product', 'user-session');
API Reference
ductape.sessions methods
| Method | Description |
|---|---|
start(data) | Start a session; returns token, refreshToken, sessionId, expiresAt |
verify(data) | Verify a token; returns { valid, data?, sessionId?, expiresAt? } |
refresh(data) | Refresh using refreshToken; returns new tokens |
revoke(data) | Invalidate a session (sessionId or identifier) |
listActive(data) | List active sessions with pagination |
create(product, payload) | Create a session configuration |
list(product) | List session configs for a product |
fetch(product, tag) | Fetch a session config by tag |
update(product, tag, payload) | Update a session config |
delete(product, tag) | Delete a session config |
fetchUsers(data) | Paginated session users |
fetchUserDetails(data) | Detailed user info and session history |
fetchDashboard(data) | Dashboard metrics for a session |
users(data) | Fetch users for a session (alternative) |
Error handling
- TypeScript
- Java
- Go
- .NET
import { SessionError } from '@ductape/sdk';
try {
const result = await ductape.sessions.verify({ ... });
} catch (error) {
if (error instanceof SessionError) {
console.log('Error code:', error.code);
console.log('Message:', error.message);
}
}
import Map.of( SessionError ) from '@ductape/sdk';
try Map.of(
Map<String, Object> result = ductape.sessions.verify(Map.of( ... ));
) catch (error) Map.of(
if (error instanceof SessionError) Map.of(
System.out.println('Error "code", ", error.code);
System.out.println("Message:', error.message);
)
)
import { SessionError } from '@ductape/sdk';
try {
result := client.sessions.verify({ ... });
} catch (error) {
if (error instanceof SessionError) {
fmt.Println('Error "code": ", error.code);
fmt.Println("Message:', error.message);
}
}
import { SessionError } from '@ductape/sdk';
try {
var result = await ductape.sessions.verify({ ... });
} catch (error) {
if (error instanceof SessionError) {
Console.WriteLine('Error ["code"] = ", error.code);
Console.WriteLine("Message:', error.message);
}
}