180 lines
5.5 KiB
Markdown
180 lines
5.5 KiB
Markdown
# 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
|
|
|