Signed Session Token
No JWT infrastructure? Sign a tiny JSON payload with a shared secret you register in Studio. Buddy verifies the signature in constant time and rejects expired tokens.
Token format
The token is intentionally not a JWT. It is two base64url segments joined by a dot:
token = base64url(JSON payload) + "." + base64url(HMAC_SHA256(payloadB64, secret))
Payload
Include whatever identity you want the agent to know, plus an exp (unix seconds). A userId is required.
{
"userId": "user_123",
"email": "ada@example.com",
"role": "customer",
"plan": "pro",
"iat": 1717000000,
"exp": 1717000300
}
Anything that isn't userId, email,
role, exp, iat or nbf
becomes a custom attribute. Tokens are capped to a short maximum lifetime
by the platform regardless of exp.
Example: mint a token
// Node — no JWT library needed.
import crypto from 'node:crypto';
function signSessionToken(payload, secret) {
const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
const sig = crypto.createHmac('sha256', secret).update(body).digest('base64url');
return body + '.' + sig;
}
const token = signSessionToken(
{ userId: user.id, email: user.email, role: user.role,
iat: Math.floor(Date.now() / 1000), exp: Math.floor(Date.now() / 1000) + 300 },
process.env.BUDDY_SHARED_SECRET
);
# Python
import base64, hmac, hashlib, json, time
def sign_session_token(payload, secret):
body = base64.urlsafe_b64encode(json.dumps(payload).encode()).rstrip(b"=")
sig = hmac.new(secret.encode(), body, hashlib.sha256).digest()
sig_b64 = base64.urlsafe_b64encode(sig).rstrip(b"=")
return body.decode() + "." + sig_b64.decode()
Troubleshooting
| Code | Meaning & fix |
|---|---|
AUTH_TOKEN_MALFORMED | Not two base64url segments split by a dot. Re-check your encoding. |
AUTH_TOKEN_INVALID | Signature mismatch. Confirm both sides use the same secret and sign the payload segment bytes. |
AUTH_TOKEN_EXPIRED | The exp passed or the token exceeded the platform lifetime ceiling. |
AUTH_TOKEN_NO_SUBJECT | No userId in the payload. |