# Kosmi Authentication Discovery ## Date: November 1, 2025 ## Summary Investigation into Kosmi's email/password authentication mechanism reveals a non-standard implementation that requires further reverse engineering. ## Findings ### 1. GraphQL API Analysis **Endpoint**: `https://engine.kosmi.io/` **Available Mutations**: ```bash $ ./bin/test-introspection | jq '.data.__schema.mutationType.fields[] | .name' "anonLogin" "slackLogin" ``` **Key Discovery**: There is NO `login`, `emailLogin`, or `passwordLogin` mutation in the GraphQL API. ### 2. Anonymous Login (Working) The `anonLogin` mutation works and is currently implemented: ```graphql mutation { anonLogin { token user { id displayName } } } ``` ### 3. Email/Password Login (Mystery) **Observations**: - Email/password login works successfully in the browser - After login, a JWT token appears in `localStorage` with key `"token"` - Example token payload: ```json { "aud": "kosmi", "exp": 1793465205, "iat": 1762015605, "iss": "kosmi", "jti": "1c7f9db8-9a65-4909-92c0-1c646103bdee", "nbf": 1762015604, "sub": "4ec0b428-712b-49d6-8551-224295 45d29b", "typ": "access" } ``` - Token expires in ~1 year - Algorithm: HS512 **REST API Endpoints Found**: ```bash # Both return 400 with empty error message POST https://engine.kosmi.io/auth/login POST https://engine.kosmi.io/login # Response format: { "errors": [ { "message": "" } ] } ``` **Tested Request Formats** (all failed): ```json {"email": "...", "password": "..."} {"username": "...", "password": "..."} ``` ### 4. Possible Authentication Mechanisms #### Theory 1: Client-Side JWT Generation - The browser might be generating JWTs client-side - This would be a security concern but would explain why there's no server endpoint - Would require extracting the signing key from the JavaScript bundle #### Theory 2: Hidden Authentication Flow - The password might be hashed/processed client-side before transmission - Could be using SRP (Secure Remote Password) or similar protocol - Would require analyzing the minified JavaScript #### Theory 3: Separate Authentication Service - Kosmi might use a third-party auth service (not Firebase/Auth0/Cognito - those were checked) - The service might not be directly accessible via HTTP #### Theory 4: WebSocket-Based Authentication - Authentication might happen over the WebSocket connection - The REST endpoints might be red herrings ### 5. Browser Monitoring Attempts Multiple attempts were made to capture the authentication request: - Playwright network interception (failed - page reloads cleared interceptors) - JavaScript fetch() hooking (failed - page reloads) - Browser MCP tools (successful login but couldn't capture request body) **Successful Test**: - Used browser MCP tools to log in with credentials: `email@email.com` / `password` - Login succeeded - Token appeared in localStorage - But the actual HTTP request was not captured ## Current Implementation Status ### ✅ Working - Anonymous authentication via `anonLogin` GraphQL mutation - Token storage and usage for WebSocket connections - Automatic reconnection with token refresh ### ❌ Not Working - Email/password authentication - Token refresh (no `refreshToken` mutation found in GraphQL API) ## Recommendations ### Option 1: Anonymous-Only (Current State) - Document that only anonymous login is supported - Users can still connect to rooms anonymously - This is sufficient for basic bot functionality ### Option 2: Manual Token Provision - Allow users to provide a pre-obtained token in the config - Users would log in via browser, extract token from localStorage - Bot uses the provided token directly - **Pros**: Simple, works immediately - **Cons**: Tokens expire (though they last ~1 year), manual process ### Option 3: Deep Reverse Engineering - Download and deobfuscate `core.js` (~several MB) - Find the authentication logic - Replicate it in Go - **Pros**: Full automation - **Cons**: Time-consuming, fragile (breaks if Kosmi updates their code) ### Option 4: Browser Automation - Use Playwright/Chromedp to automate browser login - Extract token from localStorage after login - Use token for bot connection - **Pros**: Works with any auth changes - **Cons**: Requires browser, more complex setup ## Next Steps 1. **Immediate**: Implement Option 2 (Manual Token Provision) - Add `Token` field to config - If provided, skip `anonLogin` and use the token directly - Document how users can extract their token 2. **Future**: Attempt Option 3 if user provides more information - User might have insights into how their own auth works - Could provide network HAR file from browser DevTools 3. **Alternative**: Contact Kosmi - Ask if they have a documented API for bots - Request official authentication method ## Test Credentials Used - Email: `email@email.com` - Password: `password` - These credentials successfully logged in via browser ## Files Created During Investigation - `cmd/test-login/main.go` - Test GraphQL login mutations - `cmd/test-introspection/main.go` - GraphQL schema introspection - `cmd/monitor-auth/main.go` - Playwright-based traffic monitoring (had issues) ## Conclusion Kosmi's email/password authentication uses a non-standard mechanism that is not exposed through their GraphQL API. Further investigation would require either: 1. Deep analysis of their minified JavaScript 2. User providing more information about the auth flow 3. Implementing manual token provision as a workaround