Authentication
API (JWT)
- Access token: 15-minute expiry, HS256
- Refresh token: 7-day expiry
- All protected routes require
Authorization: Bearer {access_token}
MCP server
The MCP server supports dual transport:- stdio (Claude Code local): No auth needed, runs as a local process
- Streamable HTTP (remote clients): OAuth 2.0 Authorization Code + PKCE
- Dynamic Client Registration (RFC 7591)
- Token lifetimes: access 1h, refresh 30d
- Metadata discovery at
/.well-known/oauth-authorization-server
MCP_AUTH_TOKEN) is supported for backward compatibility.
Auth toggle
AUTH_ENABLED=false disables auth for local development. When disabled, only expose on localhost.
User isolation
Every query on user-owned data filters byuser_id. Two layers enforce this:
- Application-level: Services explicitly filter by
user_idin WHERE clauses - Database-level: Row-level security (RLS) policies on 9 tables
Password handling
- Hashed with argon2id
- Legacy bcrypt hashes rehashed transparently on login
- Never logged or returned in responses
- Minimum 8 characters
LLM data consent
User data is never sent to external LLMs without explicit opt-in:LLM_CONSOLIDATION=false(default): Similar memories concatenated locallyLLM_CONSOLIDATION=true: Enables OpenAI API call for intelligent synthesis- The
statusMCP tool reports the current consent state
Environment secrets
Required in production:JWT_SECRET, DATABASE_URL, OPENAI_API_KEY.
Never commit secrets to git. Use .env files excluded via .gitignore.