Sessions & Cross-App SSO
The session cookie
Every sign-in method (password+TOTP, passkey, social) produces the same browser session:
| Property | Value |
|---|---|
| Cookie name | camel_session |
| Max-Age | 30 days |
| Flags | HttpOnly, Secure, SameSite=Lax, Path=/ |
| Sliding expiry | Yes — every authenticated request extends it another 30 days and updates last_used_at |
The cookie lives in the system browser (Custom Tab on Android, the normal browser on web). That shared cookie is the entire SSO mechanism.
How cross-app SSO works
No special code is required in client apps:
- User signs in via Bajeti → Camel Accounts sets
camel_sessionin the browser - Later, Simamia redirects to
/oauth/authorize - Server sees a valid session → skips login entirely
- If Simamia's consent was already granted → skips consent too
- User is back in Simamia with a code before the splash screen finishes
Bajeti login ──► session cookie set
Simamia authorize ──► session found ──► consent already granted? ──► instant code
Ngamia authorize ──► same ──► first time: one consent tap onlyAndroid requirement: launch the flow in Custom Tabs, never a WebView. A WebView has its own cookie jar — SSO breaks and PKCE guarantees weaken. AppAuth-Android does this correctly by default.
Managing sessions programmatically
Users own their sessions through the Cockpit; these endpoints power that UI.
List sessions
curl -s -b cookies.txt "$ISSUER/sessions"{
"success": true,
"data": [
{
"id": "5e8a…",
"device_label": "google",
"ip_address": "41.86.176.12",
"created_at": "2026-08-20T14:22:05Z",
"last_used_at": "2026-08-26T08:15:31Z",
"is_current": true
},
{
"id": "c2d9…",
"device_label": null,
"ip_address": "197.157.200.44",
"created_at": "2026-07-02T10:03:00Z",
"last_used_at": "2026-08-25T19:48:12Z",
"is_current": false
}
]
}device_label is the social provider name for social logins (google/github), otherwise null. Most-recently-used first.
Revoke one session
curl -s -b cookies.txt -X DELETE "$ISSUER/sessions/c2d9…"
# { "success": true, "message": "session revoked" } (404 if not owned/not found)Log out
curl -s -b cookies.txt -X POST "$ISSUER/auth/logout"
# revokes this session server-side AND clears the cookieConnections ("the door")
Everything the user ever approved lives in their connections list:
curl -s -b cookies.txt "$ISSUER/connections"{
"success": true,
"data": [
{
"client_id": "bajeti-web-x7k2p9",
"client_name": "Bajeti Web",
"scope": "openid profile",
"granted_at": "2026-07-17T12:00:00Z"
}
]
}Revoking one connection is immediate and thorough: consent deleted, refresh-token family revoked, live access tokens killed. From your app's perspective the user is simply logged out on next API call.
curl -s -b cookies.txt -X DELETE "$ISSUER/connections/bajeti-web-x7k2p9"
# { "success": true, "message": "connection revoked" }What logs users out globally
| Action | Effect |
|---|---|
| Password reset | Revokes all browser sessions of the user |
| Account deletion | Everything goes, cascaded via foreign keys |
| Session revoke (per-session) | Just that device |
| Connection revoke / client delete | All tokens for that user+app pair |
| Refresh-token reuse detection | Entire family for that user+client pair |
Your app should treat an unexpected 401 from userinfo as "session may be gone" → fall back to interactive login.