This repository has been archived on 2026-04-03. You can view files and clone it, but cannot push or open issues or pull requests.
nyx/src/composables/auth.ts
Nico a0fee6c121 Connect nyx to assay backend end-to-end
- ws.ts: auth via query params (token + session), store session_id
  from assay session_info, mark connected on ready signal
- useAgentSocket.ts: handlers for session_info, controls, artifacts, cleared
- auth.ts: auto-set dev service token for instant login
- Dockerfile + nginx.conf for K3s deployment
- .env.production: wss://assay.loop42.de/ws

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 21:16:28 +02:00

81 lines
3.2 KiB
TypeScript

import { ref, type Ref } from 'vue';
import router from '../router';
const SESSION_TOKEN_KEY = 'nyx_session';
import { getApiBase } from '../utils/apiBase';
// Dev service token — auto-login for development
const DEV_TOKEN = '7Oorb9S3OpwFyWgm4zi_Tq7GeamefbjjTgooPVPWAwPDOf6B4TvgvQlLbhmT4DjsqBS_D1g';
export function useAuth(connectFn: () => void) {
// Auto-set dev token if no token exists
if (!localStorage.getItem(SESSION_TOKEN_KEY) && !localStorage.getItem('titan_token')) {
localStorage.setItem(SESSION_TOKEN_KEY, DEV_TOKEN);
}
const isLoggedIn: Ref<boolean> = ref(!!localStorage.getItem(SESSION_TOKEN_KEY));
const loginToken: Ref<string> = ref('');
const loginError: Ref<string> = ref('');
const loggingIn: Ref<boolean> = ref(false);
async function doLogin(): Promise<void> {
const token = loginToken.value.trim();
if (!token) return;
loggingIn.value = true;
loginError.value = '';
try {
const nonceRes = await fetch(`${getApiBase()}/api/auth/nonce`);
if (!nonceRes.ok) { loginError.value = 'Auth unavailable'; loggingIn.value = false; return; }
const { nonce } = await nonceRes.json();
const res = await fetch(`${getApiBase()}/api/auth`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token, nonce }),
});
if (!res.ok) {
const err = await res.json().catch(() => ({ error: 'Login failed' }));
loginError.value = err.error || 'Invalid token';
loggingIn.value = false;
return;
}
const { sessionToken } = await res.json();
localStorage.removeItem('titan_token');
localStorage.removeItem('nyx_token');
localStorage.setItem(SESSION_TOKEN_KEY, sessionToken);
sessionStorage.removeItem('agent');
isLoggedIn.value = true;
connectFn();
router.push('/chat');
setTimeout(() => { loggingIn.value = false; }, 500);
} catch {
loginError.value = 'Network error';
loggingIn.value = false;
}
}
async function doLogout(disconnectFn?: () => void): Promise<void> {
const sessionToken = localStorage.getItem(SESSION_TOKEN_KEY);
if (sessionToken) {
// Fire-and-forget revoke
fetch(`${getApiBase()}/api/auth/logout`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sessionToken }),
}).catch(() => {});
}
if (disconnectFn) disconnectFn();
localStorage.removeItem(SESSION_TOKEN_KEY);
localStorage.removeItem('titan_token');
localStorage.removeItem('nyx_token');
sessionStorage.removeItem('agent');
sessionStorage.removeItem('viewer_auth'); // clear cached fstoken
isLoggedIn.value = false;
loginToken.value = '';
loggingIn.value = false;
router.push('/');
}
return { isLoggedIn, loginToken, loginError, loggingIn, doLogin, doLogout };
}